<?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=Andy</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=Andy"/>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Spezial:Beitr%C3%A4ge/Andy"/>
		<updated>2026-04-11T20:44:55Z</updated>
		<subtitle>Benutzerbeiträge</subtitle>
		<generator>MediaWiki 1.25.1</generator>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=AVR-Einstieg_leicht_gemacht&amp;diff=11958</id>
		<title>AVR-Einstieg leicht gemacht</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=AVR-Einstieg_leicht_gemacht&amp;diff=11958"/>
				<updated>2007-05-08T20:28:58Z</updated>
		
		<summary type="html">&lt;p&gt;Andy: /* Wie bekommt man das Programm in den Controller? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Bild:avr8.jpg|thumb|300px|Einen Controller zum Leben zu erwecken ist nicht schwer, manchmal reichen ein paar Teile! Beispiel mit Mega8]]&lt;br /&gt;
==Wir starten mit einem ATMega32== &lt;br /&gt;
Immer wieder gibt es in Foren, wie dem Roboternetz, Einsteiger, die das erstemal mit einem [[Microcontroller]] in Berührung kommen. Trotz zahlreicher Einstiegsbeiträge im Forum wiederholen sich doch bestimmte Anfängerfragen immer wieder, daher soll dieser Artikel noch einmal aufzeigen, wie man den ersten Schritt tut und einen Controller zum Leben erweckt. Es werden verschiedene Grundschaltungen aufgezeigt und erläutert, welche Bauteile welche Funktion besitzen.&lt;br /&gt;
Als Controller verwenden wir einen [[AVR]] [[ATMega32]], der derzeit größte [[AVR]]-Controller, welcher noch im bastlerfreundlichen DIP-Gehäuse verfügbar ist.  Für kleine bis mittlere Projekte ein sehr empfehlenswerter Controller, zumal er preislich mit ca. 6-7 Euro noch sehr günstig ist und zudem mit seinem 40-Pin-Gehäuse reichlich Anschlussmöglichkeiten besitzt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Mega1632.gif|center]]&lt;br /&gt;
&lt;br /&gt;
Wie auf dem Bild zu sehen, verfügt auch der etwas günstigere ATMega16 über die gleiche Pinbelegung, daher könnten wir in diesem Tutorial auch diesen Typ verwenden. Der ATMega32 hat aber doppelt soviel Speicherplatz für Programmdaten (Flash), daher hat man für eine geringe Preisdifferenz doch mehr Möglichkeiten.&lt;br /&gt;
Wer noch 3 bis 4 Euro sparen will, dem sei der [[ATMega8]] oder [[ATMega168]] empfohlen, diese Typen sind sehr ähnlich, so dass das Tutorial weitgehend auch auf diese Typen bezogen werden kann. Allerdings haben diese Typen deutlich weniger Anschlussmöglichkeiten (28 Pin DIP Gehäuse). &lt;br /&gt;
&lt;br /&gt;
Die Frage, ob man mit einem fertigen Controllerboard, einer Experimentierplatine oder einem Steckbrett beginnen sollte, wurde ja in dem RN-Wissen Wiki Beitrag &amp;quot;[[Mit welchem Controllerboard fang ich an]]&amp;quot; angesprochen. In den meisten Fällen favorisiert der Autor dieses Artikels ein fertiges Controllerboard. Warum das so ist, dazu am Ende noch ein paar Anmerkungen. Dennoch soll diese Einführung schrittweise anhand eines Steckbrettes erläutert werden.&lt;br /&gt;
&lt;br /&gt;
==Start mit handelsüblichem Steckbrett==&lt;br /&gt;
Ein Steckbrett hat den Vorteil, dass man theoretisch ohne Löten alle Bauteile relativ zügig zusammenstecken kann. Bestimmte Steckkontakte innerhalb einer Reihe sind im Steckbrett miteinander verbunden, so dass man nachher pro Bauteilbeinchen noch einige Steckkontakte zum Verdrahten mit Schaltdraht oder speziell konfektionierter Litze verwenden kann.&lt;br /&gt;
&lt;br /&gt;
'''Die Vorteile eines Steckbretts:'''&lt;br /&gt;
&lt;br /&gt;
*Bauteile können ohne Löten eingesetzt und verdrahtet werden&lt;br /&gt;
*recht zügiger Schaltungsaufbau&lt;br /&gt;
*eine Schaltung kann leicht geändert oder korrigiert werden, defekte Teile sind leicht tauschbar&lt;br /&gt;
*ein Steckbrett kann auch für ganz andere Schaltungen verwendet werden&lt;br /&gt;
'''Die Nachteile eines Steckbretts gegenüber gedruckten Schaltungen und Experimentierplatinen sind:'''&lt;br /&gt;
&lt;br /&gt;
*nicht alle Bauteile passen, so dass wir doch noch etwas löten müssen&lt;br /&gt;
*nur geringer Schaltungsumfang möglich, da es schnell unübersichtlich wird&lt;br /&gt;
*sehr störanfällig wegen grosser Kabellängen, dadurch oft Funktionsstörungen&lt;br /&gt;
*Bauteile müssen zum Teil verbogen werden, damit sie passen&lt;br /&gt;
&lt;br /&gt;
Man beginnt, indem man den Controller AVR [[ATMega32]] auf das Board aufsetzt:&lt;br /&gt;
&lt;br /&gt;
[[Bild:avrtutorial_steckbrettmega32.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
==Die Grundschaltung==&lt;br /&gt;
Damit ein Controller erst mal zum Laufen kommt, benötigt man zumindest einen 10-k-Widerstand, einen 100-nF-Kondensator und eine 5V-Spannungsquelle. Das Ganze muss entsprechend dem unteren Schaltplan verschaltet werden, man spricht von einer sogenannten Grundschaltung. In dem Schaltplan wurde der Controller im Übrigen pinkompatibel als Schaltzeichen verwendet, die Pinreihenfolge ist also im Schaltplan identisch mit der echten Bauteilpin-Reihenfolge. Diese Darstellung erleichtert den Nachbau der Schaltung auf einem Steckbrett aber auch einer Experimentierplatine ungemein. Gewöhnlich verwendet man in Schaltplänen eine etwas andere Darstellung, bei der die Pins nach Funktionsgruppen geordnet sind. Bei solchen Schaltplänen muss man sich dann anhand der Pin-Nummern orientieren, man wird dies am Ende des Artikels noch bei dem IC MAX232 sehen.&lt;br /&gt;
&lt;br /&gt;
[[Bild:avrtutorial_grundschaltung_mega32.gif|center|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wenn man schon einige Grundschaltungen in anderen Tutorials gesehen hat, dann wird man bemerken, dass unsere doch noch etwas einfacher ist und weniger Bauteile benötigt.  Hier wird beispielsweise kein Quarz verwendet, da der ATMega32 auch intern einen Takt generieren kann. Wer mit dem ADC genau messen will, sollte statt der Beschaltung im Bild, zwischen Vcc und AVcc eine Spule von 10uH und einen Kondensator von 100nF zwischen AVcc und GND schalten. Will man AVcc als Referenzspannung verwenden, muss noch ein 100nF Kondensator von ARef nach GND.&lt;br /&gt;
&lt;br /&gt;
Auf dem Steckbrett sieht die obere Schaltung wie folgt aus:&lt;br /&gt;
&lt;br /&gt;
[[Bild:avrtutorial_steckbrett1.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Um den Controller in Betrieb zu nehmen, benötigt man bei dieser Schaltung ein Netzteil, das eine stabilisierte Spannung von 4 bis 5V liefert. Wir gehen erst einmal davon aus, dass man über dieses verfügt. &lt;br /&gt;
Erwähnenswert ist noch, dass der Kondensator als [[Abblockkondensator]] zur Unterdrückung von Störungen dient. Er muss so nah wie möglich an die Spannungszuführung am Controller selbst gesetzt werden. Ohne Kondensator enstehen erhebliche Störungen in der Versorgungsspannung, das Bild verdeutlicht es:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Abblockkondensator OhneC amAVR.jpg|center]]&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Der Widerstand in der Grundschaltung dient dazu, die Reset-Leitung konstant auf definiertem High-Pegel zu halten. Verbindet man diesen RESET-Pin später kurz mit GND (Masse), dann wird das Programm im Controller neu gestartet.&lt;br /&gt;
&lt;br /&gt;
==Woran merkt man, dass der Controller funktioniert?==&lt;br /&gt;
Gute Frage! Man merkt es garnicht. Genau genommen funktioniert ja auch trotz korrekter Schaltung noch immer nix, denn es muss zuerst ein Programm in den Controller geladen werden, damit er überhaupt weiss, was zu tun ist. Ohne Programm ist der Controller quasi tot.&lt;br /&gt;
&lt;br /&gt;
==Wie bekommt man das Programm in den Controller?==&lt;br /&gt;
Der Controller verfügt über eine sogenannte [[ISP]]-Schnittstelle. Das bedeutet, über bestimmte Pins ([[SPI]]) kann der Controller mit einer geeigneten PC-Software (zum Beispiel Bascom) programmiert werden. Zum Anschluss an den PC benötigt man jedoch einen sogenannten ISP-Dongle, auch Programmieradapter genannt. Hier gibt es verschiedene Lösungen, serielle und parallele Adapter. Original von Atmel oder kompatible Lösungen. Der am meisten verwendete ISP-Dongle wird am Druckerport betrieben. Diese gibt es inzwischen recht preiswert, sodass sich das Selbstbauen eigentlich nicht lohnt. Da man auch gern auf ein paar Fehlerquellen verzichten sollte, würde ich eine Fertiglösung empfehlen. Wer ihn selbst bauen möchte, findet ([[AVR-ISP_Programmierkabel|hier]] eine ISP-Dongle-Bauanleitung und sogar eine fertige Platine dafür  ([[AVR-ISP_Programmierkabel]]).&lt;br /&gt;
&lt;br /&gt;
Sowas sieht dann so aus:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Avrtutorial_ispkabel.jpeg|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Der Schaltplan eines solchen Programmierkabels:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:ispschaltplan.gif|center|thumb|400px|Schaltplan des ISP-Dongels nach unserem Wiki-Bauplan, mit SUB-D Buchse. Bitte beachten, dass das IC1 hier im Plan als verschiedene Blöcke (IC1A/IC1B) dargestellt wird. Dies dient nur zur Übersicht, es handelt sich nur um ein IC, einfach auf die Pinnummern achten. Zum vergrößern anklicken.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das Problem ist nun, wie schließe ich einen handelsüblichen ISP-Programmieradapter an den Controller auf dem Steckbrett an. Der normale 10-polige Wannenstecker (nach [[RN-Definitionen]]) passt nicht in ein Steckbrett. Das ist wieder so ein typischer Nachteil bei Steckbrettern! In unserem Beispiel haben wir dazu auf einem kleinen Stück Experimentierplatine einen steckbaren Adapter für das Steckboard gelötet.&lt;br /&gt;
Somit kann man die Schaltung um einen üblichen 10-poligen ISP-Programmieranschluss ergänzen:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:avrtutorial_grundschaltung_mitisp.gif|center|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Auf dem Steckbrett sieht das gleiche so aus:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:avrtutorial_steckbrett_mitisp.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Jetzt endlich ist es soweit, jetzt kann man den Controller über einen ISP-Programmieradapter mit dem PC verbinden. Aber unbedingt darauf achten, dass auch alles korrekt nach Schaltplan gesteckt wurde und dass die Betriebsspannung 5V nicht übersteigt. Ansonsten könnte man sich Dongle oder sogar die PC-Schnittstelle beschädigen.&lt;br /&gt;
Als Entwicklungsumgebung nutzen wir hier im Tutorial [[Bascom]]. [[Bascom]] ist ein sehr beliebter Basic-[[Compiler]], der zahlreiche [[AVR]] Controllertypen programmieren kann. Da auch ein [[Terminalprogramm]] und ein Programmer integriert ist, enthält diese PC-Software alles, was man braucht, das erleichtert den Einstieg zusätzlich. Die Software gibts kostenlos als Demo bis 4K Code, für unsere Beispiele und den Einstieg reicht das allemal, siehe dazu Artikel Bascom.&lt;br /&gt;
Wie man ein Programm schreibt, kompiliert und überträgt, wurde schon in diesem Beitrag [[Bascom - Erstes Programm in den AVR Controller übertragen]] ausführlich behandelt, wir ersparen uns deshalb diese Details. &lt;br /&gt;
&lt;br /&gt;
Als erstes kompilieren und übertragen wir folgendes Programm:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
'###################################################&lt;br /&gt;
'step1.bas.BAS&lt;br /&gt;
'für&lt;br /&gt;
'RoboterNetz.de AVR Tutorial in RN-Wissen&lt;br /&gt;
'&lt;br /&gt;
'Autor: Frank Brall&lt;br /&gt;
'Weitere Beispiele und Beschreibung der Hardware&lt;br /&gt;
'unter&lt;br /&gt;
'  http://www.Roboternetz.de oder&lt;br /&gt;
'  http://www.Roboternetz.de/wissen&lt;br /&gt;
'#######################################################&lt;br /&gt;
&lt;br /&gt;
$regfile = &amp;quot;m32def.dat&amp;quot;&lt;br /&gt;
$framesize = 32&lt;br /&gt;
$swstack = 32&lt;br /&gt;
$hwstack = 32&lt;br /&gt;
$crystal = 1000000&lt;br /&gt;
&lt;br /&gt;
Do&lt;br /&gt;
Loop&lt;br /&gt;
&lt;br /&gt;
End&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Programm macht eigentlich nichts, außer dass es eine Endlosschleife ausführt. Aber da wir noch überhaupt nix am Controller angeschlossen haben, können wir eh noch nicht sehen, ob ein Programm nun richtig ausgeführt wird oder nicht.&lt;br /&gt;
Allerdings können wir schonmal üben, das Programm mit Bascom zu übertragen. Wenn wir alles richtig aufgebaut haben und Spannung anliegt, dann sollte automatisch der Controller in Bascom erkannt werden. Die Übertragung sollte dann ohne Fehlermeldung erfolgen können. Wenn wir das geschafft haben, geht’s weiter.&lt;br /&gt;
&lt;br /&gt;
==Läuft die Schaltung und das Programm?==&lt;br /&gt;
Damit wir nun endlich sehen, ob sich bei unserer Schaltung auch was tut, schließen wir eine LED über einen 1K-Vorwiderstand an einen Port an. Da wir die Kathode an den Controllerpin und die Anode an Plus legen, leuchtet die LED immer dann, wenn dieser Pin auf Low geschaltet wird.&lt;br /&gt;
&lt;br /&gt;
[[Bild:avrtutorial_grundschaltung_mitled.gif|center|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Auf dem Steckbrett sieht's nun so aus:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:avrtutorial_steckbrett_mitled.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Damit man nun auch wirklich sieht, ob das Programm läuft, schreiben wir ein kleines Basic-Programm, welches eine LED abwechselnd ein– und ausschaltet. Wir kompilieren und übertragen also folgendes Programm:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
'###################################################&lt;br /&gt;
'step2.bas.BAS&lt;br /&gt;
'für&lt;br /&gt;
'RoboterNetz.de AVR Tutorial in RN-Wissen&lt;br /&gt;
'&lt;br /&gt;
'Autor: Frank Brall&lt;br /&gt;
'Weitere Beispiele und Beschreibung der Hardware&lt;br /&gt;
'unter&lt;br /&gt;
'  http://www.Roboternetz.de oder&lt;br /&gt;
'  http://www.Roboternetz.de/wissen&lt;br /&gt;
'#######################################################&lt;br /&gt;
&lt;br /&gt;
$regfile = &amp;quot;m32def.dat&amp;quot;&lt;br /&gt;
$framesize = 32&lt;br /&gt;
$swstack = 32&lt;br /&gt;
$hwstack = 32&lt;br /&gt;
$crystal = 1000000&lt;br /&gt;
&lt;br /&gt;
Config Portc.0 = Output       'Ein Pin wird aus Ausgang konfiguriert PC0 (also Pin0 von Port C)&lt;br /&gt;
&lt;br /&gt;
Do&lt;br /&gt;
  Portc.0 = 1                 'Pin wird auf High, also 5V geschaltet&lt;br /&gt;
  Waitms 100&lt;br /&gt;
  Portc.0 = 0                 'Pin wird auf Low, also 0V geschaltet&lt;br /&gt;
  Waitms 100&lt;br /&gt;
Loop&lt;br /&gt;
&lt;br /&gt;
End&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wenn die LED nun schnell blinkt, dann funktioniert die aufgebaute Schaltung perfekt. Wir haben gleichzeitig gelernt, wie man einen Ausgangsport, also Controllerpin, ein- und ausschalten kann. Nahezu alle Pins beim ATMega32 können auf diese Weise als Ausgangsport betrieben werden. Somit lassen sich nicht nur viele Leds, sondern unter Zuhilfenahme eines Treibers (z.B. Transistors) auch Relais und andere Aktoren schalten.&lt;br /&gt;
&lt;br /&gt;
==Eingangsport fragt Taster ab==&lt;br /&gt;
Nun erweitern wir die Schaltung noch um einen Taster. Nahezu jedes Port kann bei einem ATMega32 auch per Software als Eingangsport konfiguriert werden. Wir schließen z.B. einen Taster an Port-Pin PA7 an. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:avrtutorial_grundschaltung_mittaster.gif|center|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das Port wird in der Software so konfiguriert, dass es als Eingang arbeitet und intern über einen hohen Widerstand  (Pullup-Widerstand) ständig auf High-Pegel gelegt wird. Wird nun eine Taste gedrückt, so wird der Pegel auf Low gezogen.&lt;br /&gt;
Das Beispielprogramm ist nun so gestaltet, dass bei gedrückter Taste die LED leuchtet und beim Loslassen wieder ausgeht.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
'###################################################&lt;br /&gt;
'step3.bas.BAS&lt;br /&gt;
'für&lt;br /&gt;
'RoboterNetz.de AVR Tutorial in RN-Wissen&lt;br /&gt;
'&lt;br /&gt;
'Autor: Frank Brall&lt;br /&gt;
'Weitere Beispiele und Beschreibung der Hardware&lt;br /&gt;
'unter&lt;br /&gt;
'  http://www.Roboternetz.de oder&lt;br /&gt;
'  http://www.Roboternetz.de/wissen&lt;br /&gt;
'#######################################################&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
$regfile = &amp;quot;m32def.dat&amp;quot;&lt;br /&gt;
$framesize = 32&lt;br /&gt;
$swstack = 32&lt;br /&gt;
$hwstack = 32&lt;br /&gt;
$crystal = 1000000&lt;br /&gt;
&lt;br /&gt;
Config Portc.0 = Output        'Ein Pin wird aus Ausgang konfiguriert PC0 (also Pin0 von Port C)&lt;br /&gt;
&lt;br /&gt;
Config Pina.7 = Input          'Ein Pin (PA0) wird als Eingang definiert&lt;br /&gt;
Porta.7 = 1                    'Interner Pullup Widerstand ein&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Do&lt;br /&gt;
  If Pina.7 = 1 Then&lt;br /&gt;
    Portc.0 = 1                'Pin wird auf High, also 5V geschaltet&lt;br /&gt;
  Else&lt;br /&gt;
    Portc.0 = 0                'Pin wird auf Low, also 0V geschaltet&lt;br /&gt;
  End If&lt;br /&gt;
Loop&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
End&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Grundschaltung mit Quarz==&lt;br /&gt;
Obwohl wir ab der letzten Schaltung schon einiges mit dem Controller anfangen können, so fehlt doch noch etwas Wichtiges. Oft ist es nämlich notwendig, dass ein Controller sehr genaue Frequenzen mißt oder ganz genaue Taktraten ausgeben kann. Leider ist der interne Taktgenerator nicht 100% exakt, was bei manchen Anwendungen störend ist. Zum Beispiel können über die RS232-Schnittstelle Daten nicht immer ganz fehlerfrei übertragen werden, wenn die Taktfrequenz nicht genau stimmt. Daher wird in den meisten Anwendungsfällen ein Quarz zur Takterzeugung genutzt, Sie kennen das sicher aus anderen Grundschaltungen. Also erweitern wir unsere Schaltung gleich noch um einen Quarz mit den zugehörigen 22pF-Kondensatoren.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:avrtutorial_grundschaltung_mitquarz.gif|center|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Auf unserem Steckbrett wird's langsam voller, hier sieht's also inzwischen so aus:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:avrtutorial_steckbrett_mitquarz.jpg|center|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Normalerweise sollte der Quarz genauso wie die beiden 22pF-Kondensatoren, die zum Anschwingen des Quarzes dienen, möglichst nahe am Controller platziert werden. Auf dem Steckbrett ist das manchmal gar nicht so einfach, insbesondere wenn man wie in diesem Fall den Quarz erst später hinzufügt. Wichtig ist nämlich, dass die Leitungen vom Quarz zum Controller möglichst kurz sind, bei gedruckten Schaltungen oft nur 1 bis 2 cm! Auch die einzelnen Bauteilbeinchen, z.B. der Kondensatoren, sollten normalerweise so kurz wie möglich sein.&lt;br /&gt;
Ist dies nicht der Fall, wie auch in unserem Bild, dann fungieren diese Leitungen fast wie eine Funkantenne. Dies führt in der Regel zu starken Hochfrequenzsignalen, die nicht nur unsere Schaltung, sondern auch andere Schaltungen in der Nähe stören könnten. Man merkt dies auch oft daran, dass sich ein Board bei höherer Quarzfrequenz immer seltener fehlerfrei ohne Übertragungsfehler programmieren läßt.&lt;br /&gt;
Grundsätzlich sind daher Schaltungen mit Quarz auf einem Steckbrett nicht sonderlich zu empfehlen, die Betriebssicherheit ist nicht immer gegeben. &lt;br /&gt;
&lt;br /&gt;
Auch wenn nun ein Quarz angeschlossen ist, so wird er noch immer nicht genutzt. Noch immer arbeitet der [[ATMega32]] mit seiner intern voreingestellten 1 Mhz Taktfrequenz. Um dies umzustellen, muss man ein sogenanntes [[Fusebits|Fusebit]] im Controller umprogrammieren. Auch dies wurde schon im Beitrag [[Bascom - Erstes Programm in den AVR_Controller übertragen]] näher beschrieben. Hier sei daher nur nochmals gesagt, dass dies auch sehr bequem in [[Bascom]] erfolgt:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:avrtutorial_bascomfusebitquarz.gif|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Sobald wir das umgestellt haben, müssen wir auch in dem Programm die Anweisung &lt;br /&gt;
&lt;br /&gt;
 $crystal = 1000000 &lt;br /&gt;
&lt;br /&gt;
durch &lt;br /&gt;
&lt;br /&gt;
 $crystal = 16000000 &lt;br /&gt;
&lt;br /&gt;
ersetzen, denn unser Quarz taktet nun mit 16 MHz.&lt;br /&gt;
&lt;br /&gt;
==Spannung stabilisieren==&lt;br /&gt;
Auch wenn unsere Basis-Schaltung für Experimente inzwischen schon ganz nett ist, so ist es doch etwas ungünstig, dass wir stets 5V zur Verfügung haben müssen. Nicht immer steht ein geeignetes Netzteil zur Verfügung, zudem soll ein Controller auch oft mit Batterien versorgt werden. Aus diesem Grund verfügen fast alle Entwicklungsboards wie ([[RN-Control]], STK500 etc.) über einen [[Spannungsregler]].&lt;br /&gt;
[[Bild:78s05.jpg|thumb|Spannungsregler 78S05]] Dieser wandelt eine höhere Eingangsspannung (ca. 7 bis 20 V) immer genau in  5V  um. Sowas erhöht die Betriebssicherheit einer Schaltung nochmals immens. Als [[Spannungsregler]] (IC2) wird oft der 7805 genutzt, empfehlenswert ist der Typ 78S05, welcher 2A verträgt sowie über einen Kurzschluss- und Überlastungsschutz verfügt. &lt;br /&gt;
Die beiden 100nF-Kondensatoren sind wichtig, sie sollen HF-Störungen und Schwingungen vermeiden. Der Elko vor dem Spannungsregler ist vor allem dann wichtig, wenn die Spannung von einem Netzgerät kommt und noch etwas geglättet werden muss. Je höher der Strombedarf der Schaltung, desto größer kann man die Kapazität wählen. Es schadet nicht, wenn man den Elko einige Nummern größer wählt, man ist dann quasi für alle Fälle gerüstet. So sind Werte zwischen 100 uF und 2200 uF durchaus denkbar. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Wir erweitern unsere Schaltung somit wie folgt:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:avrtutorial_grundschaltung_spannung.gif|center|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Auf dem Steckbrett sieht's wie folgt aus:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:avrtutorial_steckbrett_spannung.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
==Daten und Texte zum PC übertragen==&lt;br /&gt;
In vielen Programmen müssen Daten oder Texte vom Controller an den PC oder umgekehrt gesendet werden. Insbesondere bei komplexen Programmen kann man auf diese Weise Variableninhalte ausgeben und somit auch Fehler im Programmcode schneller finden und korrigieren. In der Regel ist das ganz einfach, denn der [[Microcontroller]] [[ATMega32]] verfügt über einen internen [[UART]], also ein Modul, das Daten über die [[RS232]]-Schnittstelle zum PC senden bzw. auch von ihm empfangen kann. Leider arbeitet jedoch die Controllerschnittstelle mit 5V und die PC-Schnittstelle der Norm entsprechend mit +-12V. Daher muss unbedingt ein Schaltkreis dazwischen, welcher die Pegel anpasst. Gewöhnlich nimmt man hier das IC MAX232(CPE), welches inzwischen sehr preiswert erhältlich ist.&lt;br /&gt;
&lt;br /&gt;
Wir müssen also die Schaltung nochmals erweitern.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:avrtutorial_grundschaltung_max232.gif|center|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Das IC Max232 ist im Schaltplan in der üblichen funktionsorientierten Darstellung gezeichnet. Zur besseren Übersichtlichkeit wurden die immer benötigten Anschlüsse für VCC (Pin 16) und GND (Pin 15) getrennt oben rechts im Schaltplan dargestellt. Also nicht vergessen !!&lt;br /&gt;
&lt;br /&gt;
Auf dem Steckbrett sieht's so aus:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:avrtutorial_steckbrett_max232.jpg|center|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Über eine dreipolige Stiftleiste ([[RN-Definitionen]]) wird nun das Steckboard mit der [[RS232]]-Schnittstelle des PC verbunden. Es ist nun ein Leichtes, mit einem Programm Daten zum PC zu senden. Das nachfolgende Programm gibt Hinweise mit der Anweisung '''PRINT''' aus:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
'###################################################&lt;br /&gt;
'step5.bas.BAS&lt;br /&gt;
'für&lt;br /&gt;
'RoboterNetz.de AVR Tutorial in RN-Wissen&lt;br /&gt;
'&lt;br /&gt;
'Autor: Frank Brall&lt;br /&gt;
'Weitere Beispiele und Beschreibung der Hardware&lt;br /&gt;
'unter&lt;br /&gt;
'  http://www.Roboternetz.de oder&lt;br /&gt;
'  http://www.Roboternetz.de/wissen&lt;br /&gt;
'#######################################################&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
$regfile = &amp;quot;m32def.dat&amp;quot;&lt;br /&gt;
$framesize = 32&lt;br /&gt;
$swstack = 32&lt;br /&gt;
$hwstack = 32&lt;br /&gt;
$crystal = 16000000&lt;br /&gt;
$baud = 9600&lt;br /&gt;
&lt;br /&gt;
Config Portc.0 = Output              'Ein Pin wird aus Ausgang konfiguriert PC0 (also Pin0 von Port C)&lt;br /&gt;
&lt;br /&gt;
Config Pina.7 = Input                'Ein Pin (PA0) wird als Eingang definiert&lt;br /&gt;
Porta.7 = 1                          'Interner Pullup Widerstand ein&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Do&lt;br /&gt;
  If Pina.7 = 1 Then&lt;br /&gt;
    Portc.0 = 1                      'Pin wird auf High, also 5V geschaltet&lt;br /&gt;
    Print &amp;quot;Schalter nicht gedrückt&amp;quot;&lt;br /&gt;
  Else&lt;br /&gt;
    Portc.0 = 0                      'Pin wird auf Low, also 0V geschaltet&lt;br /&gt;
    Print &amp;quot;Schalter gedrückt&amp;quot;&lt;br /&gt;
  End If&lt;br /&gt;
  Wait 1&lt;br /&gt;
Loop&lt;br /&gt;
&lt;br /&gt;
End&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Möglichkeiten des Steckbrettes erreicht==&lt;br /&gt;
Inzwischen füllt der Schaltplan fast ein DIN-A4-Blatt und auf dem Steckbrett sieht's auch schon recht wirr aus, dabei haben wir nur die wichtigsten Grundelemente auf dem Steckbrett. Für eine Roboter-Steuerung oder andere Anwendung fehlt doch noch einiges. Zum Beispiel weitere Taster, weitere LEDs, Motortreiber, damit der Controller auch Motoren ansteuern kann und ein [[I2C]]-Bus-Anschluss.&lt;br /&gt;
Dies alles noch auf einem Steckbrett zu realisieren macht wenig Sinn, zumal bereits jetzt schon durch die doch recht langen Leitungen/Verkabelungen erhebliche Störungen auftreten. In der letzten Phase ist es immer öfters zu Übertragungsfehlern beim Programmieren gekommen, oft musste dies 20mal wiederholt werden. Dies zeigt, dass ein Steckbrett bestenfalls für ganz kleine Controller-Experimente herhalten kann. Für größere Dinge sollte man dann doch zu einer Lösung auf einer gedruckten Platine greifen. Spezielle Experimentierboards  bieten mehr Sicherheit und haben neben den Grundelementen, die hier beschrieben wurden, noch eine ganze Menge mehr drauf. Bei [[RN-Control]] zum Beispiel 5 Tasten, 8 Leds, Motortreiber, Lautsprecher, diverse Anschlüsse etc. &lt;br /&gt;
Der Größenunterschied wird im Bild deutlich:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:avrtutorial_steckbrett_rncontrol.jpg|center|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Auch wenn das Steckbrett also kein Controllerboard ersetzen kann, so hat das kleine Tutorial doch gezeigt, wie eine [[Avr]]-Schaltung aufzubauen ist. Dieses Wissen sollte man auch besitzen, wenn man ein Controllerboard nutzt. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Was braucht man, wenn man mit einem Controllerboard den Einstieg startet?==&lt;br /&gt;
&lt;br /&gt;
[[Bild:avrtutorial_ispkabel.jpg|thumb|ISP-Programmierkabel]]Neben dem eigentlichen Board braucht man, wie schon zuvor angesprochen, ein [[AVR-ISP Programmierkabel]]. Da das Selbstbauen kaum billiger ist, ist zu empfehlen, ein solches fertig mitzubestellen. Am preiswertesten und zugleich vielseitigsten sind die ISP-Adapter, die man an das Druckerport anschließt (siehe Bild). Es gibt aber auch USB-Lösungen, wobei diese jedoch oft teuer sind und auch oft weniger Controller programmieren können. Hat man jedoch einen PC oder Notebook ohne parellelen Druckeranschluss, so muss man wohl oder übel in den meisten Fällen zu einem seriellen oder USB-Programmieradapter greifen. Neben den erwähnten Nachteilen hat der USB Dongle aber oft auch den Vorteil, dass er etwas schneller ist. Dieser Unterschied macht sich aber nur bei sehr großen Programmen und Controllern wirklich bemerkbar.&lt;br /&gt;
&lt;br /&gt;
Als zweites braucht man natürlich eine Stromversorgung. Ideal sind Gleichspannungsnetzgeräte, die zwischen 9 und 12V liefern, vorausgesetzt, das Board hat einen Spannungsregler wie in der Regel die RN-Boards. Man kann hier ein normales Steckernetzteil oder ein komfortables Labornetzteil nehmen. Um etwas Reserve zu haben, wäre es gut, wenn das Netzteil mindestens 1 A liefern kann. Alternativ kann man auch Akkupacks oder Batterien nutzen, allerdings mindestens 7,2V sollten die schon liefern können, sicherer sind 8,4-, 9,6- oder 12V-Akkus.&lt;br /&gt;
Das wäre eigentlich schon das Wichtigste, um ein Board in Betrieb zu nehmen und Experimente zu machen. &lt;br /&gt;
&lt;br /&gt;
Allerdings, ein RS232-Kabel ist ebenfalls noch sehr empfehlenswert. Dieses erlaubt die Ausgabe von Texten und Variablen auf den PC, wir haben es ja oben im Steckbrettbeispiel schon gesehen. Dazu wird auf dem PC ein [[Terminalprogramm]] gestartet und über die [[RS232]] Schnittstelle mit dem PC verbunden. Bei manchen Boards ist sowieso ein RS232 Kabel unerläßlich, wie z.B. RN-Motor, RN-Speak etc. Nützlich ist es aber überall. Man kann ein solches Kabel selbst bauen oder gleich beim Kauf eines Boardes mitbestellen.&lt;br /&gt;
&lt;br /&gt;
Also nochmal die Zusammenfassung für den Einstieg:&lt;br /&gt;
&lt;br /&gt;
* Controllerboard&lt;br /&gt;
* [[AVR-ISP Programmierkabel]] mit 10-poligem Wannenstecker&lt;br /&gt;
* RS-232-Kabel (mit 3-poligem Adapter, wenn Board [[RN-Definitionen]] erfüllt)&lt;br /&gt;
* Netzgerät oder Akku (ideal 9 bis 12V, notfalls auch 7,2 bis 20V)&lt;br /&gt;
* [[Bascom]]-Compiler-Vollversion ist nur nötig, wenn man gleich größere Sachen anstrebt, ansonsten reicht das Demo, genauso wie ein [[Avr-gcc]]-Compiler. Bei RN-Boards sind diese Programme beim Board- oder Platinenkauf sowieso dabei, ansonsten kann man diese im Internet downloaden.&lt;br /&gt;
* Ein gutes Buch ist immer gut, siehe [[Buchvorstellungen]]&lt;br /&gt;
&lt;br /&gt;
==Autor==&lt;br /&gt;
*[[Benutzer:Frank|Frank]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Quellen===&lt;br /&gt;
* [[Abblockkondensator]] Artikel von Uwegw&lt;br /&gt;
* RN-Board Dokumentationen aus [[:Kategorie:Projekte]]&lt;br /&gt;
* diverse Datenblätter&lt;br /&gt;
&lt;br /&gt;
==Siehe auch==&lt;br /&gt;
*[[AVR-ISP Programmierkabel]]&lt;br /&gt;
*[[Mit welchem Controllerboard fang ich an]]&lt;br /&gt;
*[[Abblockkondensator]]&lt;br /&gt;
*[[Bascom]]&lt;br /&gt;
*[[Bascom - Erstes Programm in den AVR_Controller übertragen]]&lt;br /&gt;
*[[Avr]]&lt;br /&gt;
*[[Atmel Controller Mega16 und Mega32]]&lt;br /&gt;
*[[Spannungsregler]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Robotikeinstieg]]&lt;br /&gt;
[[Kategorie:Praxis]]&lt;br /&gt;
[[Kategorie:Elektronik]]&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Projekte]]&lt;/div&gt;</summary>
		<author><name>Andy</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=RN-Control&amp;diff=11957</id>
		<title>RN-Control</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=RN-Control&amp;diff=11957"/>
				<updated>2007-05-08T19:15:30Z</updated>
		
		<summary type="html">&lt;p&gt;Andy: /* Programmierung per Druckerport, USB oder RS232 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ein bewährtes Microcontrollerboard, das wie das RNBFRA-Board in der Roboternetz-Community infolge einer Diskussion entstand. Es sollte ein Board werden, das ein gutes Preis-Leistungs-Verhältnis bietet und für vielfältige Aufgaben geeignet ist. &lt;br /&gt;
Das Vorhaben ist dank der zahlreichen Anregungen gut gelungen, das Board gibt es inzwischen nicht nur als Bauanleitung mit Platine, sondern auch als Bausatz und sogar Fertigmodul.&lt;br /&gt;
Es hat sich als preiswertes Universalboard für Roboter, Steuerungsaufgaben etc. als auch als ideales Einsteigerboard einen guten Namen im Roboternetz gemacht, daher gibt es für dieses Board auch ein eigenes Unterforum im Roboternetz.  &lt;br /&gt;
Es gibt inzwischen unzählige Anwendungen, die mit RN-Control umgesetzt wurden.&lt;br /&gt;
Trotz günstigem Preis ist ein sehr flexibles Board für unzählige Anwendungsmöglichkeiten entstanden. Über den I2C-Bus stehen zahlreiche Erweiterungsboards zur Verfügung, so können beispielsweise die gleichen I2C-Erweiterungen wie beim großen RNBFRA-Board kombiniert werden (Relaiskarte, Sprachausgabe usw.) Roboternetz &lt;br /&gt;
&lt;br /&gt;
[[Bild:rncontrol1.4diagramm.jpg|thumb|Funktionen des Boards]]&lt;br /&gt;
&lt;br /&gt;
[[Bild:rncontrol1.4schaltplan.gif|thumb|Schaltplan zum Board]]&lt;br /&gt;
&lt;br /&gt;
[[Bild:rncontrol1.4bestückungsplan.gif|thumb|Bestückungsplan zum Board]]&lt;br /&gt;
&lt;br /&gt;
Besonders viel Wert wurde auch auf den einfachen Aufbau und viele Experimentier- und Einsatzmöglichkeiten gelegt. Mit diesem Board läßt sich u.a. schon ein recht ausgereifter Roboter konstruieren. Ultraschallsensoren, Infrarot-Entfernungssensoren, Motoren u.v.m. können direkt angeschlossen werden. Da das Board auch in der Community Roboternetz recht beliebt ist, findet man dort auch viele Tips und Programme. &lt;br /&gt;
&lt;br /&gt;
[[http://www.robotikhardware.de/bilder/rncontrol14diagrammmittel.jpg Diagramm hier]]&lt;br /&gt;
&lt;br /&gt;
==Hier die Leistungsmerkmale auf einen Blick:==&lt;br /&gt;
&lt;br /&gt;
*Wahlweise 8 oder 16 Mhz Taktfrequenz (beide Quarze werden mitgeliefert, 16 Mhz bereits eingesteckt) &lt;br /&gt;
*Schneller AVR Mega 32  Mikrocontroller,32K Speicher, 2K Ram und 1K EEPROM), 32 programmierbare I/O Pins,8 AD Ports u.v.m. &lt;br /&gt;
*8 Leuchtdioden per DIP-Schalter deaktivierbar und anderen Ports per Steckbrücke beliebig zuzuordnen &lt;br /&gt;
*alle Portleitungen sind über Stecker nach außen geführt. Die Steckernorm entspricht der Roboternetz-Definition als auch der des Atmel Entwicklungsboards STK500 &lt;br /&gt;
*alle Ports sowie +5V und GND sind zusätzlich über Steckbuchsen erreichbar. Ideal zum Experimentieren, da einfach Drähte (ca. 0,5mm) eingesteckt werden (kein Löten oder Schrauben). So können einfach andere LEDs zugeordnet werden oder ein Steckbrett verbunden werden &lt;br /&gt;
*Der wichtige Port A (wahlweise 8 digitale oder analoge Ein- o. Ausgänge) ist zusätzlich noch über eine Qualitätssteckklemme mit Hebel herausgeführt &lt;br /&gt;
*Motortreiber ca. 1 A belastbar - für zwei Getriebemotoren oder 1 Schrittmotor. Dieser kann auch für andere Zwecke (Relaisansteuerung, Lämpchen etc.) genutzt oder einfach entfernt werden &lt;br /&gt;
*Integrierter programmierbarer Mini-Lautsprecher, um Töne auszugeben &lt;br /&gt;
*1 Reset-Taster &lt;br /&gt;
*5 Taster für beliebige Verwendung. Sie belegen nur einen analogen Port! &lt;br /&gt;
*5 V Spannungsstabilisierung mit 2 A Belastbarkeit, auch herausgeführt für Erweiterungen; Eingangsspannung gegen Verpolung geschützt &lt;br /&gt;
*RS232 mit normgerechtem Pegelwandler (MAX232) - PC direkt anschließbar &lt;br /&gt;
*Batteriespannung kann im Programm abgefragt werden &lt;br /&gt;
*ISP-Programmierschnittstelle für übliche AVR-Programmieradapter (10polig) &lt;br /&gt;
*Betriebsspannung wahlweise zwischen 7 und 18V (empfohlen 7 bis 14 V) - wahlweise auch höhere Motorspannung bis 24 V möglich) &lt;br /&gt;
*Sehr kompakt, nur halbes Europaformat nach Roboternetz-Norm (ca. 100x75mm) &lt;br /&gt;
*I2C-Bus, über den zahlreiche Erweiterungsplatinen anschließbar sind (z.B. Sprachausgabe RN-Speak, Relaisboard RN-Relais, Servoboards, LCDs uvm.) &lt;br /&gt;
*Programmierbar in zahlreichen Sprachen, z.B. Basic (BASCOM Compiler, eingeschränkt bis 4K wird mitgeliefert), C (C-Compiler GCC wird mitgeliefert), Assembler, Pascal &lt;br /&gt;
*Deutsche Doku mit Basic-Programmbeispiel &lt;br /&gt;
*Preiswerter Bausatz erhältlich - einfacher Aufbau &lt;br /&gt;
*Kein Starter- oder Applikationsboard notwendig - bereits alles integriert! &lt;br /&gt;
*alle wichtigen Bauteile gesockelt, somit auch bei falscher Beschaltung durch Einsteiger immer kostengünstig reparierbar (einfach neues IC einstecken) &lt;br /&gt;
&lt;br /&gt;
http://www.robotikhardware.de/bilder/rncontro4.jpg&lt;br /&gt;
&lt;br /&gt;
==Belegung der RN-Control Steckklemmen==&lt;br /&gt;
Um auch schnell und praktisch mit RN-Control experimentieren zu können, verfügt dieses Board über Steckklemmen die alle Ports herausführen. 0,5mm Drähte lassen sich dort direkt einstecken, so das Sensoren und dergleichen schnell und einfach verdrahtet werden können. Die genaue Belegung lässt sich in nachfolgendem Ausschnitt aus dem Bestückungsplan gut entnehmen.&lt;br /&gt;
&lt;br /&gt;
[[Bild:rncontrolsteckklemmen.gif|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Steckerbelegung und Jumper-Funktionen==&lt;br /&gt;
Erläuterung der Anschlüsse, Regler und Kurzschlussbrücken&lt;br /&gt;
&lt;br /&gt;
{|{{Blauetabelle}}&lt;br /&gt;
|'''Anschluss-Bezeichnung'''&lt;br /&gt;
|'''Erläuterung'''&lt;br /&gt;
|-&lt;br /&gt;
|'''Port A'''&lt;br /&gt;
|Digitaler I/O und analoger Port (PA 0 bis PA7 und ADC0 bis ADC7)&lt;br /&gt;
Über  eine Steckklemme werden hier die 8 Portleitungen PA0 bis PA 7 zur Verfügung gestellt. PA7 befindet sich dabei ganz links und PA0 ganz rechts. Anschlußdrähte können einfach eingesteckt werden, indem man mit einem Kugelschreiber oder Schraubenziehen den oberen weißen Hebel etwas nach unten drückt.&lt;br /&gt;
Die Ports PA7 bis PA0 können sowohl als normaler I/O-Port  (Ein- und Ausgabeport) oder als AD-Port´s programmiert werden. Somit könnten also auch bis zu 8 Spannungen quasi gleichzeitig gemessen werden. &lt;br /&gt;
&lt;br /&gt;
Ist der Kurzschlusstecker  UREF eingesteckt, dann können Spannungen bis zu 5V gemessen werden. Ist UREF offen, dann können Spannungen nur bis 2,5V gemessen werden. Durch geeignete Spannungsteiler kann der Meßbereich natürlich beliebig erhöht werden.&lt;br /&gt;
&lt;br /&gt;
Achtung: Die zulässige Höchstspannung 2,5V oder 5V darf am Port nicht überschritten werden, dieses würde den Port zerstören! &lt;br /&gt;
&lt;br /&gt;
Vorbelegung:&lt;br /&gt;
Port  PA7 wird auch für die Tastenabfrage genutzt. indem über einen Spannungsteiler verschiedene Spannungen per Tastendruck angelegt werden (siehe Schaltplan). &lt;br /&gt;
Solange keine Taste gedrückt ist, ist dieser jedoch frei Verfügbar.&lt;br /&gt;
Port PA6 wird über einen Spannungsteiler (22k und 5,1K) zur Batteriespannungsmessung benutzt  (siehe Schaltplan und Demoprogramm) wenn der Kurzschlusstecker UMESS eingesteckt ist.  Durch entfernen dieses Steckers steht der Port zur freien Verfügung.&lt;br /&gt;
&lt;br /&gt;
Der komplette Port steht auch nochmals über die Buchsenleiste JP2 zur Verfügung. Auch dort können Drähte zum experimentieren eingesteckt werden (möglichst 0,6mm²). &lt;br /&gt;
|-&lt;br /&gt;
|'''Port B'''&lt;br /&gt;
|Digitale I/O Port B  (PB0 bis PB 7)&lt;br /&gt;
Über einen Wannenstecker werden gemäß der Roboternetz-Definition 8 I/O Portleitungen mit Sonderfunktionen als auch GND und +5V bereitgestellt. &lt;br /&gt;
&lt;br /&gt;
Die genaue Belegung sieht wie folgt aus:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Pin 1   PB0  /  T0 / XCL / wird vom Motortreiber für Motor 2 Kanal 1 genutzt&lt;br /&gt;
Pin 2   PB1  /  T1 / wird vom Motortreiber für Motor 2 Kanal 2 genutzt&lt;br /&gt;
Pin 3   PB2  /  AIN0 / INT2  / wird auch vom I2C-Bus genutzt&lt;br /&gt;
Pin 4   PB3  /  AIN1 / OC0&lt;br /&gt;
Pin 5   PB4  /  SS&lt;br /&gt;
Pin 6   PB5  /  MOSI / wird auch vom ISP Anschluss genutzt&lt;br /&gt;
Pin 7   PB6  /  MISO / wird auch  vom ISP Anschluss genutzt&lt;br /&gt;
Pin 8   PB7  /  SCK / wird auch  vom ISP Anschluss genutzt&lt;br /&gt;
Pin 9   GND&lt;br /&gt;
Pin 10  +5V&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Durch entfernen des Motortreiber IC´s aus der Fassung, steht PB0 und PB1 zur freien Verfügung.&lt;br /&gt;
&lt;br /&gt;
Der komplette Port steht auch nochmals über die Buchsenleiste JP3 zur Verfügung. Auch dort können Drähte zum experimentieren eingesteckt werden (möglichst 0,6mm²).&lt;br /&gt;
|-&lt;br /&gt;
|'''Port C'''&lt;br /&gt;
|Digitale I/O Port C  (PC0 bis PC 7)&lt;br /&gt;
Über einen Wannenstecker werden gemäß der Roboternetz-Definition 8 I/O Portleitungen mit Sonderfunktionen als auch GND und +5V bereitgestellt. &lt;br /&gt;
&lt;br /&gt;
Die genaue Belegung sieht wie folgt aus:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Pin 1   PC0  /  SCL wird vom I2C-Bus genutzt&lt;br /&gt;
Pin 2   PC1  /  SDA wird vom I2C-Bus genutzt&lt;br /&gt;
Pin 3   PC2  /  TCK&lt;br /&gt;
Pin 4   PC3  /  TMS&lt;br /&gt;
Pin 5   PC4  /  TDO&lt;br /&gt;
Pin 6   PC5  /  TDI&lt;br /&gt;
Pin 7   PC6  /  TOSC1 / wird vom Motortreiber für Motor 1 Kanal 1 genutzt&lt;br /&gt;
Pin 8   PC7  /  TOSC2 / wird vom Motortreiber für Motor 1 Kanal 2 genutzt&lt;br /&gt;
Pin 9   GND&lt;br /&gt;
Pin 10  +5V&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Über den 8 fachen DIP Schalter können den Ports auch LED´s zugeschaltet werden! Die LED´s leuchten wenn Port LOW-Zustand annimmt!&lt;br /&gt;
&lt;br /&gt;
Durch entfernen des Motortreiber IC´s aus der Fassung, steht PC6 und PC7 zur freien Verfügung.&lt;br /&gt;
Der komplette Port steht auch nochmals über die Buchsenleiste JP4 zur Verfügung. Auch dort können Drähte zum experimentieren eingesteckt werden (möglichst 0,6mm²).&lt;br /&gt;
|-&lt;br /&gt;
|'''Port D'''&lt;br /&gt;
|Digitale I/O Port D  (PD0 bis PD 7)&lt;br /&gt;
Über einen Wannenstecker werden gemäß der Roboternetz-Definition 8 I/O Portleitungen mit Sonderfunktionen als auch GND und +5V bereitgestellt. &lt;br /&gt;
&lt;br /&gt;
Die genaue Belegung sieht wie folgt aus:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Pin 1   PD0  /  RXD / wird für RS232 Schnittstelle genutzt&lt;br /&gt;
Pin 2   PD1  /  TXD  / wird für RS232 Schnittstelle genutzt&lt;br /&gt;
Pin 3   PD2  /  INT0&lt;br /&gt;
Pin 4   PD3  /  INT1 &lt;br /&gt;
Pin 5   PD4  /  OC1B  / wird für PWM Motor 1 benutzt (Geschwindigkeitsregelung)&lt;br /&gt;
Pin 6   PD5  /  OC1A  / wird für PWM Motor 2 benutzt (Geschwindigkeitsregelung)&lt;br /&gt;
Pin 7   PD6  /  ICP&lt;br /&gt;
Pin 8   PD7  /  OC2&lt;br /&gt;
Pin 9   GND&lt;br /&gt;
Pin 10  +5V&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Durch entfernen des Motortreiber IC´s aus der Fassung, steht PD4 und PD5 zur freien Verfügung.&lt;br /&gt;
Der komplette Port steht auch nochmal über die Buchsenleiste JP5 zur Verfügung. Auch dort können Drähte zum experimentieren eingesteckt werden (möglichst 0,6mm²).&lt;br /&gt;
|-&lt;br /&gt;
|'''I2C-Bus'''&lt;br /&gt;
|I2C-Bus&lt;br /&gt;
Über diesen Bus lassen sich zahlreiche Erweiterungen an dieses Board anschließen. Zum Beispiel werden auf der Seite robotikhardware.de passende Boards mit Sprachausgabe, Relais, Schrittmotorsteuerung etc. angeboten.&lt;br /&gt;
Aber auch dieses Board kann selbst als Slave-Board, also als Erweiterung an ein anderes Hauptboard angeschlossen werden.&lt;br /&gt;
Der I2C-Bus benötig nur 2 Leitungen für alle Funktionen. Entsprechend der Roboternetz-Norm wird hier ein 2x5 poliger Stecker angeschlossen. Die Belegung entspricht exakt der anderer Roboternetz Boards.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Pin 1 SCL (Taktleitung)&lt;br /&gt;
Pin 3 SDA (Datenleitung)&lt;br /&gt;
Pin 5 +5V&lt;br /&gt;
Pin 7 +5V&lt;br /&gt;
Pin 9  Batteriespannung&lt;br /&gt;
Pin 2,4,6,8 GND&lt;br /&gt;
Pin 10  INT&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
INT - Diese Leitung kann von allen I2C-Bus Erweiterungen genutzt &lt;br /&gt;
werden um den Hauptcontroller darüber zu informieren das sich Daten (z.B. von Sensoren) verändert haben. In diesem Fall wird die Leitung solange auf Masse gelegt bis der entsprechende  I2C-Baustein ausgelesen wird.&lt;br /&gt;
Die Controller muß also immer alle I2C-Bausteine auslesen solange diese Leitung auf Masse liegt. Diese Leitung ist mit Port PD2 verbunden&lt;br /&gt;
&lt;br /&gt;
Die PIN´s 5,7,9 und 10 können über  herausnehmbare Kurzschlussbrücken (Jumper JP6) vom Board getrennt werden. Dies ist zum Beispiel dann notwendig, wenn bereits ein anderes Masterboard die Spannungen auf den Bus legt. Es darf immer nur ein Board die Spannungen bereitstellen.&lt;br /&gt;
|-&lt;br /&gt;
|'''ISP'''&lt;br /&gt;
|ISP – IN SYSTEM PROGRAMMING&lt;br /&gt;
Über diesen Anschluß kann der  Controller auf dem Sprachboard mit einem Standard ISP-Kabel direkt an einen Parallelport des PC´s angeschlossen und programmiert werden.&lt;br /&gt;
Die Belegung des ISP-Anschlusses ist zu dem weit verbreitetet STK200 Programmier Dongle kompatibel. Ein entsprechender Dongle kann man sich entweder selber basteln (siehe Artikel „ARV Einstieg leicht gemacht“ unter www.roboternetz.de) oder fertig bestellen (z.B. www.robotikhardware.de). &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Pin 1 MOSI&lt;br /&gt;
Pin 2 VCC&lt;br /&gt;
Pin 3 Nicht belegt&lt;br /&gt;
Pin 4 GND&lt;br /&gt;
Pin 5 RESET&lt;br /&gt;
Pin 6 GND&lt;br /&gt;
Pin 7 SCK&lt;br /&gt;
Pin 8 GND&lt;br /&gt;
Pin 9 MISO&lt;br /&gt;
Pin 10 GND &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|'''Power'''&lt;br /&gt;
|Spannungsversorgung&lt;br /&gt;
Über diese Schraubklemme wird das Board mit Spannung versorgt. Es reicht eine unstabilisierte Gleichspannung von 7 bis 14V aus (max. 18V wenn Kühlkörper verwendet wird)&lt;br /&gt;
+ und – sind auf der Platine markiert. Das Board ist jedoch auch gegen ein verpolen geschützt, so das nichts kaputt geht!&lt;br /&gt;
|-&lt;br /&gt;
|'''Motoren'''&lt;br /&gt;
|Motoren&lt;br /&gt;
Über diese 4 polige Schraubklemme können zwei Getriebemotoren (jeweils die beiden linken oder rechten Kontakte) oder ein Schrittmotor angeschlossen werden. &lt;br /&gt;
Der Motortreiber kann jedoch auch für andere Dinge genutzt werden, z.B zum Ansteuern von Relais, Lämpchen etc. verwendet werden. Die Belastbarkeit liegt bei 1A.  Sollen größere Motoren angeschlossen werden,  so kann z.B. über den I2C-Port eine andere Endstufe angeschlossen werden. &lt;br /&gt;
|-&lt;br /&gt;
|'''JP6'''&lt;br /&gt;
|I2C-Bus Belegung&lt;br /&gt;
Über drei Kurzschlussstecker können wahlweise die Bateriespannung (UB), +5V sowie INT mit dem I2C-Bus verbunden werden. Wenn INT nicht benötigt wird, kann man diesen Jumper offen lassen. Somit hat man einen Port zusätzlich frei zur Verfügung&lt;br /&gt;
Möchte man das Board über den I2C-Bus mit Spannung versorgen, dann kann man UB oder +5V Jumper einstecken. In diesem Fall braucht/darf keine Spannung an dem Power Schraubklemen angelegt werden. Möchte man umgekehrt andere Boards über den I2C-Bus mit Spannung versorgen, dann müssen die Jumper UB und/oder +5V eingesteckt werden. &lt;br /&gt;
Durch diesen Jumper ist man für alle Fälle gerüstet. Bei älteren RN-Control Versionen mußte man dazu noch das Kabel ändern.&lt;br /&gt;
|-&lt;br /&gt;
|'''JP8'''&lt;br /&gt;
|Über diesen Stecker kann die stabilisierte 5V Logikspannung für Erweiterungen oder Experimente entnommen werden. Wird mehr als 500mA entnommen, so sollte der Spannungsregler  mit einem kleinen Kühlkörper versehen werden.&lt;br /&gt;
|-&lt;br /&gt;
|'''UREF'''&lt;br /&gt;
|Referenzspannung&lt;br /&gt;
Über eine Kurzschlussstecker kann hier die Referenzspannung von 5V eingestellt werden. Wird der Stecker entfernt, so kann an den analogen Ports nur bis 2,5V gemessen werden (jedoch mit höherer Genauigkeit). &lt;br /&gt;
Sicherheitshalber sollten Sie den Stecker anfangs eingesteckt lassen!  Wird er entfernt, so sollte man daran denken das auch die Batteriespannung über einen analogen Port gemessen wird. Diese darf dann nicht viel höher als 13V  sein!&lt;br /&gt;
|-&lt;br /&gt;
|'''UMOT'''&lt;br /&gt;
|Motorspannung&lt;br /&gt;
Wenn dieser Kurzschlussstecker eingesteckt wird, dann wird die volle Batteriespannung auch für die Motoren benutzt. Ansonsten könnte man über einen PIN dieses Jumpers auch eine höhere Versorgungsspannung für die Motoren nutzen. Dazu sollte sie aber nochmals in den Schaltplan schaun.&lt;br /&gt;
In der Regel sollte hier ein Jumper eingesteckt sein!&lt;br /&gt;
|-&lt;br /&gt;
|'''UMESS'''&lt;br /&gt;
|Batteriespannungsmessung&lt;br /&gt;
Wenn diese Kurzschlussbrücke gesteckt ist, dann wird über Port PA6 die Batteriespannung überwacht. Ansonsten ist der Port frei!&lt;br /&gt;
|-&lt;br /&gt;
|'''S1'''&lt;br /&gt;
|DIP Schalter&lt;br /&gt;
Mit einem kleinen Schraubenzieher kann über diesen 8 poligen Schalter den Portleitungen PC0 bis PC7 eine LED zugeschaltet werden. Die LED´s leuchten immer dann wenn der Port LOW  (0 Pegel) führt.&lt;br /&gt;
Wenn die LED auf Off geschaltet wird, so kann die LED über eine Drahtbrücke von JP7 mit einem anderen Port verbunden werden.&lt;br /&gt;
|-&lt;br /&gt;
|'''RS232'''&lt;br /&gt;
|PC kompatible RS232 Schnittstelle&lt;br /&gt;
Über ein Adapterkabel kann die serielle Schnittstelle des PC direkt mit dem Board verbunden werden. Dies ist dann sinnvoll, wenn Fehler in Programmen gesucht . Einfache PRINT Anweisungen werden von einem Terminalprogramm angezeigt.&lt;br /&gt;
Hier kann Hyperterminal von Windows oder das eingebaute terminalprogramm von Bascom empfohlen werden.&lt;br /&gt;
&lt;br /&gt;
Die Belegung ist kompatibel zum Conrad Roboter CCRP5:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Pin 1 RX&lt;br /&gt;
Pin 2 GND&lt;br /&gt;
Pin 3 TX&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Ein geeignetes Anschlußkabel kann schnell selbst angefertigt werden oder gibt  es bei robotikhardware.de bereits fertig&lt;br /&gt;
|-&lt;br /&gt;
|'''JP7'''&lt;br /&gt;
|Über diese Buchse sind alle LED´s ganz einfach durch Einstecken eines Drahtes beschaltbar.&lt;br /&gt;
Bedenken muß man dabei das die Anode über einen Vorwiderstand immer mit 5V verbunden ist. Die LED leuchtet also nur wenn sie mit der Drahtbrücke auf GND bzw. einen Port mit 0 Pegel gelegt wird. &lt;br /&gt;
|-&lt;br /&gt;
|'''JP1'''&lt;br /&gt;
|Buchsenleiste die dreimal +5V und drei mal GND für Experimente bereitstellt&lt;br /&gt;
|-&lt;br /&gt;
|'''JP2'''&lt;br /&gt;
|Buchsenleiste die den gesamten Port A für steckbare Drähte bereitstellt&lt;br /&gt;
|-&lt;br /&gt;
|'''JP3'''&lt;br /&gt;
|Buchsenleiste die den gesamten Port B für steckbare Drähte bereitstellt&lt;br /&gt;
|-&lt;br /&gt;
|'''JP4'''&lt;br /&gt;
|Buchsenleiste die den gesamten Port C für steckbare Drähte bereitstellt&lt;br /&gt;
|-&lt;br /&gt;
|'''JP5'''&lt;br /&gt;
|Buchsenleiste die den gesamten Port D für steckbare Drähte bereitstellt&lt;br /&gt;
|-&lt;br /&gt;
|'''TASTER T1 bis T5'''&lt;br /&gt;
|Stehen zur freien Verfügung&lt;br /&gt;
Die Abfrage ist im Demoprogramm beschrieben&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Stückliste==&lt;br /&gt;
 Bauteil Wert       Beschreibung                   Reichelt Best.Nr.&lt;br /&gt;
 C1      100n       Keramik Kondensator            KERKO100N&lt;br /&gt;
 C2      100n       Keramik Kondensator            KERKO100N   &lt;br /&gt;
 C3      22pf       Keramik Kondensator            KERKO-500 22p           &lt;br /&gt;
 C4      22pf       Keramik Kondensator            KERKO-500 22p          &lt;br /&gt;
 C5      4,7uF      Elko                           SM 4,7/50RAD           &lt;br /&gt;
 C6      4,7uF      Elko                           SM 4,7/50RAD           &lt;br /&gt;
 C7      4,7uF      Elko                           SM 4,7/50RAD           &lt;br /&gt;
 C8      4,7uF      Elko                           SM 4,7/50RAD           &lt;br /&gt;
 C9      1uF        Elko                           SM 1,0/63RAD           &lt;br /&gt;
 C10     100n       Keramik Kondensator            KERKO100N              &lt;br /&gt;
 C11     100n       Keramik Kondensator            KERKO100N              &lt;br /&gt;
 C12     100n       Keramik Kondensator            KERKO100N              &lt;br /&gt;
 C13     1000uF     Elko                           RAD 1000/35            &lt;br /&gt;
 C14     100n       Keramik Kondensator            KERKO100N              &lt;br /&gt;
 C15     100n       Keramik Kondensator            KERKO100N              &lt;br /&gt;
 C16     100n       Keramik Kondensator            KERKO100N              &lt;br /&gt;
 C17     220uF      Elko                           RAD 220/35             &lt;br /&gt;
 C18     100n       Keramik Kondensator            KERKO100N              &lt;br /&gt;
 D1      1N4148     Diode                          1n 4148                &lt;br /&gt;
 D2      BYV27      Diode                          BYV 27/200             &lt;br /&gt;
 I2C-BUS I2C        Wannenbuchse                   WSL 10G                &lt;br /&gt;
 IC1     MAX232     RS232 Treiber                  MAX 232 CPE             &lt;br /&gt;
 IC2     7805       Spannungsregler                78S05                  &lt;br /&gt;
 IC3     L293D      Motortreiber                   L 293 D                &lt;br /&gt;
 IC4     MEGA16-P   Atmel Mega 16 oder 32          ATMEGA 16-16           &lt;br /&gt;
 ISP     AVR-ISP    Wannenbuchse                   WSL 10G                &lt;br /&gt;
 JP1                Kontaktbuchse (manuell kürzen) SPL20                  &lt;br /&gt;
 JP2                Kontaktbuchse (manuell kürzen) SPL 20                 &lt;br /&gt;
 JP3                Kontaktbuchse (manuell kürzen) SPL 20                  &lt;br /&gt;
 JP4                Kontaktbuchse (manuell kürzen) SPL 20                 &lt;br /&gt;
 JP5                Kontaktbuchse (manuell kürzen) SPL 20                 &lt;br /&gt;
 JP6                Stiftleiste                    Stiftl. 2x50g (teilen) &lt;br /&gt;
 JP7                Kontaktbuchse (manuell kürzen) SPL 20                 &lt;br /&gt;
 JP8                Stiftleiste                    LU 2,5 MS2             &lt;br /&gt;
 LED1               Leuchtdiode Low                LED 3MM 2MA GN         &lt;br /&gt;
 LED2               Leuchtdiode Low                LED 3MM 2MA GN         &lt;br /&gt;
 LED3               Leuchtdiode Low                LED 3MM 2MA GN         &lt;br /&gt;
 LED4               Leuchtdiode Low                LED 3MM 2MA GN         &lt;br /&gt;
 LED5               Leuchtdiode Low                LED 3MM 2MA GN         &lt;br /&gt;
 LED6               Leuchtdiode Low                LED 3MM 2MA GN         &lt;br /&gt;
 LED7               Leuchtdiode Low                LED 3MM 2MA GN         &lt;br /&gt;
 LED8               Leuchtdiode Low                LED 3MM 2MA GN         &lt;br /&gt;
 MOTOREN            Schraubklemme 4 polig          AKL 101-04             &lt;br /&gt;
 PORTA              Steckklemme 8 polig            WAGO 233-508           &lt;br /&gt;
 PORTB              Wannenbuchse                   WSL 10G                &lt;br /&gt;
 PORTC              Wannenbuchse                   WSL 10G                &lt;br /&gt;
 PORTD              Wannenbuchse                   WSL 10G                &lt;br /&gt;
 POWER              Schraubklemme 2 polig          AKL 101-02              &lt;br /&gt;
 Q1                 Quarz 16 Mhz                   16-HC18                &lt;br /&gt;
 R1      100k       Widerstand 100k                1/4W 100k              &lt;br /&gt;
 R2      1k         Widerstand 1k                  1/4W 1k                &lt;br /&gt;
 R3      10k        Widerstand 10k                 1/4W 10k               &lt;br /&gt;
 R4      1k         Widerstand 1k                  1/4W 1k                &lt;br /&gt;
 R5      1k         Widerstand 1k                  1/4W 1k                &lt;br /&gt;
 R6      1k         Widerstand 1k                  1/4W 1k                &lt;br /&gt;
 R7      1k         Widerstand 1k                  1/4W 1k                &lt;br /&gt;
 R8      1k         Widerstand 1k                  1/4W 1k                &lt;br /&gt;
 R9      22k        Widerstand 22k                 1/4W 22k               &lt;br /&gt;
 R10     5,1k       Widerstand 5,1k                1/4W 5,1k              &lt;br /&gt;
 R11     10k        Widerstand 10k                 1/4W 10k               &lt;br /&gt;
 R12     10k        Widerstand 10k                 1/4W 10k               &lt;br /&gt;
 R13     10k        Widerstand 10k                 1/4W 10k               &lt;br /&gt;
 R14     10k        Widerstand 10k                 1/4W 10k               &lt;br /&gt;
 RESET   TASTER3301 Minitaster liegend             TASTER 3301            &lt;br /&gt;
 RN1                Widerstandsnetzwerk            SIL 9-8 1,0k           &lt;br /&gt;
 RS232              Stiftleiste 3 polig            LU 2,5 MS3             &lt;br /&gt;
 S1                 DIP Schalter 8 polig           NT08                   &lt;br /&gt;
 SPEAKER F/CM12P    Mini Piezo Lautsprecher        SUMMER EPM 121         &lt;br /&gt;
 T1      TASTER3301 Minitaster liegend             TASTER 3301            &lt;br /&gt;
 T2      TASTER3301 Minitaster liegend             TASTER 3301            &lt;br /&gt;
 T3      TASTER3301 Minitaster liegend             TASTER 3301            &lt;br /&gt;
 T4      TASTER3301 Minitaster liegend             TASTER 3301            &lt;br /&gt;
 T5      TASTER3301 Minitaster liegend             TASTER 3301            &lt;br /&gt;
 UMESS              Stiftleiste                    LU 2,5 MS2             &lt;br /&gt;
 UMOT               Stiftleiste                    LU 2,5 MS2             &lt;br /&gt;
 UREF               Stiftleiste                    LU 2,5 MS2&lt;br /&gt;
&lt;br /&gt;
==Basic Beispieltestprogramm==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
'################################################### &lt;br /&gt;
'rncontroltest.BAS &lt;br /&gt;
'für &lt;br /&gt;
'RoboterNetz Board RN-CONTROL ab Version 1.1 &lt;br /&gt;
'Das neue preiswerte Controllerboard zum Experimentieren &lt;br /&gt;
&lt;br /&gt;
' Achtung: &lt;br /&gt;
' Diese Demo ist mit Bascom Compiler 1.11.7.7 getestet &lt;br /&gt;
&lt;br /&gt;
' &lt;br /&gt;
'Aufgabe: &lt;br /&gt;
' Dieses Testprogramm testet gleich mehrere Eigenschaften auf dem Board &lt;br /&gt;
' Den verschiedenen Tasten sind bestimmte Funktionen zugeordnet &lt;br /&gt;
' Taste 1: Zeigt Batteriespannung über RS232 an &lt;br /&gt;
' Taste 2: Angeschlossene Motoren beschleunigen und abbremsen &lt;br /&gt;
' Taste 3: Einige Male Lauflicht über LEDs anzeigen. Am I2C-Bus &lt;br /&gt;
'          darf in diesem Moment nichts angeschlossen sein &lt;br /&gt;
' Taste 4: Zeigt analoge Messwerte an allen Port A PINs über RS232 an &lt;br /&gt;
''Taste 5: Zeigt digitalen I/O Zustand von PA0 bis PA5 an &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
' Sehr gut kann man aus dem Demo auch entnehmen wie Sound ausgegeben wird, &lt;br /&gt;
' wie Tasten abgefragt werden und wie Subroutinen und Funktionen angelegt werden &lt;br /&gt;
&lt;br /&gt;
'Autor: Frank &lt;br /&gt;
'####################################################### &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Declare Sub Batteriespannung() &lt;br /&gt;
Declare Sub Motortest() &lt;br /&gt;
Declare Sub Lauflicht() &lt;br /&gt;
Declare Sub Showporta() &lt;br /&gt;
Declare Sub Showdigitalporta() &lt;br /&gt;
Declare Function Tastenabfrage() As Byte &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
$regfile = &amp;quot;m32def.dat&amp;quot; &lt;br /&gt;
' bei Mega 16 $regfile = &amp;quot;m16def.dat&amp;quot; &lt;br /&gt;
$framesize = 32 &lt;br /&gt;
$swstack = 32 &lt;br /&gt;
$hwstack = 32 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Dim I As Integer &lt;br /&gt;
Dim N As Integer &lt;br /&gt;
Dim Ton As Integer &lt;br /&gt;
&lt;br /&gt;
$crystal = 16000000                           'Quarzfrequenz &lt;br /&gt;
$baud = 9600 &lt;br /&gt;
&lt;br /&gt;
Config Adc = Single , Prescaler = Auto        'Für Tastenabfrage und Spannungsmessung &lt;br /&gt;
&lt;br /&gt;
Config Pina.7 = Input                         'Für Tastenabfrage &lt;br /&gt;
Porta.7 = 1                                   'Pullup Widerstand ein &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Const Ref = 5 / 1023                          'Für Batteriespannungsberechnung &lt;br /&gt;
&lt;br /&gt;
Dim Taste As Byte &lt;br /&gt;
Dim Volt As Single &lt;br /&gt;
&lt;br /&gt;
' Für Motorentest &lt;br /&gt;
'Ports für linken Motor &lt;br /&gt;
Config Pinc.6 = Output                       'Linker Motor Kanal 1 &lt;br /&gt;
Config Pinc.7 = Output                       'Linker Motor Kanal 2 &lt;br /&gt;
Config Pind.4 = Output                       'Linker Motor PWM &lt;br /&gt;
'Ports für rechten Motor &lt;br /&gt;
Config Pinb.0 = Output                       'Rechter Motor Kanal 1 &lt;br /&gt;
Config Pinb.1 = Output                       'Rechter Motor Kanal 2 &lt;br /&gt;
Config Pind.5 = Output                       'Rechter Motor PWM &lt;br /&gt;
Config Timer1 = Pwm , Pwm = 10 , Compare A Pwm = Clear Down , Compare B Pwm = Clear Down &lt;br /&gt;
Pwm1a = 0 &lt;br /&gt;
Pwm1b = 0 &lt;br /&gt;
Tccr1b = Tccr1b Or &amp;amp;H02                      'Prescaler = 8 &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
I = 0 &lt;br /&gt;
Sound Portd.7 , 400 , 450                    'BEEP &lt;br /&gt;
Sound Portd.7 , 400 , 250                    'BEEP &lt;br /&gt;
Sound Portd.7 , 400 , 450                    'BEEP &lt;br /&gt;
Print &lt;br /&gt;
Print &amp;quot;**** RN-CONTROL 1.4 *****&amp;quot; &lt;br /&gt;
Print &amp;quot;Das neue Experimentier- und Roboterboard&amp;quot; &lt;br /&gt;
Print &amp;quot;Weitere passende Zusatzboards bei www.robotikhardware.de&amp;quot; &lt;br /&gt;
Print &lt;br /&gt;
Do &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
   Taste = Tastenabfrage() &lt;br /&gt;
   If Taste &amp;lt;&amp;gt; 0 Then &lt;br /&gt;
&lt;br /&gt;
      Select Case Taste &lt;br /&gt;
         Case 1 &lt;br /&gt;
            Call Batteriespannung    'Taste 1 Zeigt Bateriespannung über RS232 an &lt;br /&gt;
         Case 2 &lt;br /&gt;
            Call Motortest           'Taste 2 Motoren beschleunigen und abbremsen &lt;br /&gt;
         Case 3 &lt;br /&gt;
            Call Lauflicht           'Einige Male Lauflicht über LEDs anzeigen. &lt;br /&gt;
                                     'Am I2C-Port darf in diesem Moment nichts angeschlossen sein &lt;br /&gt;
         Case 4 &lt;br /&gt;
            Call Showporta           'Zeigt Messwerte an allen Port A PINs &lt;br /&gt;
         Case 5 &lt;br /&gt;
            Call Showdigitalporta    'Zeigt digitalen I/O Zustand von PA0 bis PA5 an &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
      End Select &lt;br /&gt;
      Sound Portd.7 , 400 , 500      'BEEP &lt;br /&gt;
   End If &lt;br /&gt;
&lt;br /&gt;
   Waitms 100 &lt;br /&gt;
Loop &lt;br /&gt;
&lt;br /&gt;
End &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'Diese Unterfunktion fragt die Tastatur am analogen Port ab &lt;br /&gt;
Function Tastenabfrage() As Byte &lt;br /&gt;
Local Ws As Word &lt;br /&gt;
&lt;br /&gt;
   Tastenabfrage = 0 &lt;br /&gt;
   Ton = 600 &lt;br /&gt;
   Start Adc &lt;br /&gt;
   Ws = Getadc(7) &lt;br /&gt;
  ' Print &amp;quot;Tastenabfrage anpassen!ADC Wert ws=&amp;quot; ; Ws &lt;br /&gt;
   If Ws &amp;lt; 500 Then &lt;br /&gt;
      Select Case Ws &lt;br /&gt;
         Case 400 To 450 &lt;br /&gt;
            Tastenabfrage = 1 &lt;br /&gt;
            Ton = 550 &lt;br /&gt;
         Case 330 To 380 &lt;br /&gt;
            Tastenabfrage = 2 &lt;br /&gt;
            Ton = 500 &lt;br /&gt;
         Case 260 To 305 &lt;br /&gt;
            Tastenabfrage = 3 &lt;br /&gt;
            Ton = 450 &lt;br /&gt;
         Case 180 To 220 &lt;br /&gt;
            Tastenabfrage = 4 &lt;br /&gt;
            Ton = 400 &lt;br /&gt;
         Case 90 To 130 &lt;br /&gt;
            Tastenabfrage = 5 &lt;br /&gt;
             Ton = 350 &lt;br /&gt;
 '        Case Else &lt;br /&gt;
'              Print &amp;quot;Tastenabfrage anpassen!ADC Wert ws=&amp;quot; ; Ws &lt;br /&gt;
      End Select &lt;br /&gt;
      Sound Portd.7 , 400 , Ton                             'BEEP &lt;br /&gt;
&lt;br /&gt;
   End If &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
End Function &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'Diese Unterfunktion zeigt Batteriespannung an &lt;br /&gt;
Sub Batteriespannung() &lt;br /&gt;
Local W As Word &lt;br /&gt;
   Start Adc &lt;br /&gt;
   W = Getadc(6) &lt;br /&gt;
   Volt = W * Ref &lt;br /&gt;
   Volt = Volt * 5.2941 &lt;br /&gt;
   Print &amp;quot;Die aktuelle Spannung beträgt: &amp;quot; ; Volt ; &amp;quot; Volt&amp;quot; &lt;br /&gt;
&lt;br /&gt;
End Sub &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'Testet Motoren und Geschwindigkeitsreglung &lt;br /&gt;
Sub Motortest() &lt;br /&gt;
   'Linker Motor ein &lt;br /&gt;
   Portc.6 = 1                          'bestimmt Richtung &lt;br /&gt;
   Portc.7 = 0                          'bestimmt Richtung &lt;br /&gt;
   Portd.4 = 1                          'Linker Motor EIN &lt;br /&gt;
&lt;br /&gt;
   'Rechter Motor ein &lt;br /&gt;
   Portb.0 = 1                          'bestimmt Richtung rechter Motor &lt;br /&gt;
   Portb.1 = 0                          'bestimmt Richtung rechter Motor &lt;br /&gt;
   Portd.5 = 1                          'rechter Motor EIN &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
   I = 0 &lt;br /&gt;
   Do &lt;br /&gt;
      Pwm1a = I &lt;br /&gt;
      Pwm1b = I &lt;br /&gt;
      Waitms 40 &lt;br /&gt;
      I = I + 5 &lt;br /&gt;
   Loop Until I &amp;gt; 1023 &lt;br /&gt;
&lt;br /&gt;
   Wait 1 &lt;br /&gt;
   Do &lt;br /&gt;
      Pwm1a = I &lt;br /&gt;
      Pwm1b = I &lt;br /&gt;
      Waitms 40 &lt;br /&gt;
      I = I - 5 &lt;br /&gt;
   Loop Until I &amp;lt; 1 &lt;br /&gt;
   Pwm1a = 0                            'Linker Motor aus &lt;br /&gt;
   Pwm1b = 0                            'rechter Motor aus &lt;br /&gt;
End Sub &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
' Einige Male Lauflicht über LEDs anzeigen. Am I2C-Port darf in diesem &lt;br /&gt;
' Moment nichts angeschlossen sein &lt;br /&gt;
Sub Lauflicht() &lt;br /&gt;
&lt;br /&gt;
   Config Portc = Output &lt;br /&gt;
   Portd = 0 &lt;br /&gt;
   For N = 1 To 10 &lt;br /&gt;
      For I = 0 To 7 &lt;br /&gt;
         Portc.i = 0 &lt;br /&gt;
         Waitms 100 &lt;br /&gt;
         Portc.i = 1 &lt;br /&gt;
      Next I &lt;br /&gt;
   Next N &lt;br /&gt;
   Config Portc = Input &lt;br /&gt;
End Sub &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'Zeigt die analogen Messwerte an Port A an &lt;br /&gt;
Sub Showporta() &lt;br /&gt;
Local Ws As Word &lt;br /&gt;
&lt;br /&gt;
   Config Porta = Input &lt;br /&gt;
   For I = 0 To 5                        ' Alle internen Pullup Widerstände ein, bis auf Batteriespannungsmessungsport &lt;br /&gt;
      Porta.i = 1 &lt;br /&gt;
   Next I &lt;br /&gt;
&lt;br /&gt;
   Print &lt;br /&gt;
   Print &amp;quot;Ermittelte Messwerte an Port A:&amp;quot; &lt;br /&gt;
   For I = 0 To 7                        ' Alle Eingänge inkl. messen &lt;br /&gt;
      Start Adc &lt;br /&gt;
      Ws = Getadc(i) &lt;br /&gt;
      Volt = Ws * Ref &lt;br /&gt;
      Print &amp;quot;Pin &amp;quot; ; I ; &amp;quot; ADC-Wert= &amp;quot; ; Ws ; &amp;quot; bei 5V REF waeren das &amp;quot; ; Volt ; &amp;quot; Volt&amp;quot; &lt;br /&gt;
   Next I &lt;br /&gt;
End Sub &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'Zeigt den Zustand einiger freier I/O von Die Analogen Messwerte An Port A An &lt;br /&gt;
Sub Showdigitalporta() &lt;br /&gt;
Local Zustand As String * 6 &lt;br /&gt;
   Config Porta = Input &lt;br /&gt;
   For I = 0 To 5                        ' Alle internen Pullup Widerstände ein, bis auf Batteriespannungsmessungsport &lt;br /&gt;
      Porta.i = 1 &lt;br /&gt;
   Next I &lt;br /&gt;
&lt;br /&gt;
   Print &lt;br /&gt;
   Print &amp;quot;Ermittelter I/O Zustand Port A:&amp;quot; &lt;br /&gt;
   For I = 0 To 5                        ' Alle Eingänge inkl. messen &lt;br /&gt;
      If Pina.i = 1 Then &lt;br /&gt;
         Zustand = &amp;quot;High&amp;quot; &lt;br /&gt;
      Else &lt;br /&gt;
         Zustand = &amp;quot;Low&amp;quot; &lt;br /&gt;
      End If &lt;br /&gt;
      Print &amp;quot;Pin &amp;quot; ; I ; &amp;quot; I/O Zustand= &amp;quot; ; Pina.i ; &amp;quot; &amp;quot; ; Zustand &lt;br /&gt;
   Next I &lt;br /&gt;
End Sub&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Programmierung per Druckerport, [[USB]] oder [[RS232]]==&lt;br /&gt;
RN-Control wird üblicherweise mit einem sogenannten [[ISP]]-Dongel programmiert. Die günstigste Ausführung gibt es für einen parallelen Druckerport, siehe auch unter [[AVR-ISP Programmierkabel]]. Etwas teurer aber auch schneller ist ein USBISP-Dongel. Wie genau der Ablauf vonstatten geht wird in der Anleitung (PDF-Dokument siehe Links) genau beschrieben.&lt;br /&gt;
Seit März 2007 wird RN-Control aber auch mit installiertem Bootloader ausgeliefert. Dies hat den Vorteil, dass das Board nun auch ohne ISP-Dongel per RS232 Kabel mit dem Bascom Compiler programmiert werden kann. Dies ist recht angenehm für Notebook Besitzer, die keinen parallelen Druckerport haben und denen der USBISP-Dongel am Anfang etwas zu teuer erscheint. Nähere Hinweise dazu sind ebenfalls in der überarbeiteten PDF-Anleitung (siehe Weblinks unten auf der Seite) zu finden.&lt;br /&gt;
&lt;br /&gt;
==Anschlussbeispiele==&lt;br /&gt;
Da sich Einsteiger mit dem Anschluss von Sensoren oder Verbrauchern manchmal etwas schwer tun, hier eine Skizze, wie man zum Beispiel bestimmte Dinge wie Entfernungssensoren, Servos, Lämpchen oder Helligkeits- bzw. Temperatursensoren anschließen könnte. Bei den Lämpchen sollte man beachten, dass sie zusammen weniger als 1A Strom benötigen, da ansonsten der zuständige Treiber (Motortreiber L293D) überhitzt würde. Natürlich könnte man auch größere Lasten schalten, indem man z.B. statt den Lämpchen Relais anschließt. Auch viele weitere Sensoren könnten natürlich an die noch freien Ports angeschlossen werden, beachten muss man nur, ob der Sensor einen Digital- oder Analogport benötigt.&lt;br /&gt;
Das Servo wird in der Skizze mit 5V versorgt, daher sollte man den Spannungsregler mit einem Kühlkörper versehen.&lt;br /&gt;
&lt;br /&gt;
[[Bild:rncontrolanschlussbeispiel.png|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:srf10anrncontrol.gif|framed|center|Ultraschallmodul am I2C-Bus (mehrere möglich)]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:kompassmodul_an_rncontrol.jpg|framed|center|Auch ein elektronischer Kompass läßt sich leicht am I2C Bus anschließen]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:drehgeber_an_rncontrol.gif|center|framed|Beispielschaltung wenn man lediglich die Drehzahl ohne Drehrichtung auswerten möchte. Als Widerstand hat sich 330 Ohm als gut erwiesen. Als Sensor wurde hier ein GP1A30 verwendet]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:rnjoycontrolanrncontrol.jpg|center|framed|Auch passende Joysticks/Joypads lassen sich einfach an RN-Control anschließen]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:rn_adapter_mit_rncontrol.jpg|center|framed|Über Adapter lassen sich die Wannenstecker auch durch Steckklemmen mit Portüberwachung ersetzen. Dadurch wird die Verdrahtung noch flexibler]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:rndigicontrol.jpg|thumb|center|Digitalanzeige an RN-Control]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:srf02_i2c_rncontrol.jpg|framed|center|Der neue Ultraschallsensor SRF02 im I2C Mode über Adapter an RN-Control]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:srf02_an_rncontrol_rs232mode.jpg|framed|center|Der neue Ultraschallsensor SRF02 im RS232 Mode an RN-Control]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:rn_lcd_adapter_rncontrol.gif|framed|center|Ein LCD mittels RN-LCDAdapter angeschlossen.]]&lt;br /&gt;
&lt;br /&gt;
==Projektbeispiel mit RN-Control==&lt;br /&gt;
&lt;br /&gt;
[[Bild:allwetterbot.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Siehe auch==&lt;br /&gt;
*[[Beispiel Drehzahlmessung mit RN-Control]]&lt;br /&gt;
* [[Ultraschall SRF10 an RN-Control]]&lt;br /&gt;
* [[Ultraschallsensor SRF02 am RN-Board]]&lt;br /&gt;
* [[Bascom und Kompass CMPS03]]&lt;br /&gt;
* [[RN-Digi|4 stellige Digitalanzeige an RN-Control]]&lt;br /&gt;
* [[LCD an RN-Control]]&lt;br /&gt;
*[[Bascom]]&lt;br /&gt;
*[[Bascom - Erstes Programm in den AVR Controller übertragen]]&lt;br /&gt;
*[[RN-Definitionen]]&lt;br /&gt;
*[[RN-Board FAQ-Seite]]&lt;br /&gt;
* [[Avr]]&lt;br /&gt;
* [[RN-Mega8]] &lt;br /&gt;
* [[RNBFRA-Board]]&lt;br /&gt;
&lt;br /&gt;
==Weblinks==&lt;br /&gt;
* [http://www.roboternetz.de/phpBB2/dload.php?action=file&amp;amp;file_id=138 Ausführliche Anleitung und Bauplan als PDF-Datei]&lt;br /&gt;
&lt;br /&gt;
{{Platinenservice|http://www.robotikhardware.de}}&lt;br /&gt;
{{Bausatzservice|http://www.robotikhardware.de}}&lt;br /&gt;
{{Fertigservice|http://www.robotikhardware.de}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Robotikeinstieg]]&lt;br /&gt;
[[Category:Praxis]]&lt;br /&gt;
[[Category:Elektronik]]&lt;br /&gt;
[[Category:Projekte]]&lt;br /&gt;
[[Category:Microcontroller]]&lt;br /&gt;
[[Kategorie:Quellcode Bascom]]&lt;/div&gt;</summary>
		<author><name>Andy</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=11917</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=11917"/>
				<updated>2007-05-06T19:48:22Z</updated>
		
		<summary type="html">&lt;p&gt;Andy: /* Variablen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einladung zur Diskussion... =&lt;br /&gt;
&lt;br /&gt;
Es wird hier versucht die ASM Programmierung von PIC Mikrocontrollern möglichst kurz zu beschreiben.&lt;br /&gt;
&lt;br /&gt;
Damit der enstehende Artikel wirklich nützlich  wird, ist Ihre Mitwirkung nötig. Bitte schreiben Sie uns Ihre Meinung, was eventuell noch geändert (z.B. ergänzt) werden soll in diesem Thread:&lt;br /&gt;
&lt;br /&gt;
http://www.roboternetz.de/phpBB2/viewtopic.php?p=271211#271211&lt;br /&gt;
&lt;br /&gt;
Die Autoren bedanken sich im voraus für jeden Beitrag mit Vorschlägen !&lt;br /&gt;
&lt;br /&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 enhä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, u.s.w. 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 Mid-Range hat 14-bitige Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bitige 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 3 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. (INDF 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 ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 14-bittigen 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 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. Siehe: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von Mid-Range PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 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 Mid-Range Serie 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 (beim PIC 14 bit) 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 (fatch)        &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 kleinen eigenen Speicher, der weder zum Programmspeicher noch zum Datenspeicher gehört. Er besteht aus dem Programmzähler PC (programm counter) und dem Stapel (stack).&lt;br /&gt;
&lt;br /&gt;
In dem PC befindet sich die 13-Bittige Adresse des momentan ausfürbaren 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 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. Damit es möglich wäre, 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). &lt;br /&gt;
&lt;br /&gt;
Der Stapel kann aber nur 8 Adressen speichern, deswegen dürfen nur 8 nacheinander folgende &amp;quot;call&amp;quot; Befehle benutzt werden. Sonst findet der Prozessor nicht mehr zurück und in die &amp;quot;Nirvana&amp;quot; springt, was einen Absturz des Programms bedeutet.&lt;br /&gt;
&lt;br /&gt;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen Mid-Range 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 200 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 eigebundenen 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.&lt;br /&gt;
&lt;br /&gt;
Dank der integrierten oder an Portpins angeschlosenen Hardware und dem entsprechenden Program 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. 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 die wichtigsten 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 Texdatei 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) intalliert 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 Eischalten 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, u.s.w.). Bei diesen reicht es bereits Spannung anzulegen und sie laufen bereits.&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, u.s.w.) 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 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 MCLR Pin angeschlossene Hardware während der Programmierung zu schützen. &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 Versorgungspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF möglichts 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 vermeinden, 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 Program 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;
== 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össe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Grösse des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, u.s.w.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, u.s.w.).&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ägiges 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. PIC Trainer) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bischen 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 Program 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. Hautprogram (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 Programs 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, u.s.w. 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 eledigt 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 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 Texdatei 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 Assembler 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 dannn 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;
== Programmdurchlaufdiagramm ==&lt;br /&gt;
&lt;br /&gt;
Der Programdurchlaufdiagram (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 (ausser &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 Komputerprogramme 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 Program 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 eifach 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;
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; (Sleep) agewendet 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, endweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung. &lt;br /&gt;
&lt;br /&gt;
Als allgemeinnutziges 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 Hauptprogram 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 gesammten 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; gekenzeichnet 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. Ausserdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, u.s.w.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, u.s.w.) 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 Quelcode 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|Mausrad]]&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 Hauptprogram 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 fogender 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 der CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (ausser 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 der 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 Hauptprogram 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.&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 eigeschrieben:&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) aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&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 &lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Program 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 asführen kann, muss er vollständig und richtig 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 meistens 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                b.z.w.           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 alle Ports nacheinander gelöscht und 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   PORTA &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anchliessend werden für jeden Port die Werte in TRIS Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRIS 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 TRIS 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 TRASB 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 TRIS 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) b.z.w. nur als Eingang benutzt werden können. Bei Plannung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich ein bestimmter Pin für die geplannte 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, u.s.w.), 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 Herstellern 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;
                               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;
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;
                                        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 bestimmtes 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]].&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 ) u.s.w. &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;
=== 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 dennen ist, dass die Sprungtabellen steuern den Programlauf 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 veschiedenen 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üch zum Aufrufer der Tabelle.&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, 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      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	dt      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	dt      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	dt      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	dt      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	dt      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   u.s.w.&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 0x00 enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator fur 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 Programms, 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, 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 im Programm verursachen.&lt;br /&gt;
&lt;br /&gt;
Um ein Interrupt auslösen zu können, muss er in UP &amp;quot;Init&amp;quot;, durch beschreiben nötigen Register (INTCON, PIR, u.s.w.) 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.&lt;br /&gt;
&lt;br /&gt;
==== Interrupt Service Routine ====&lt;br /&gt;
&lt;br /&gt;
Die Interrupt Service Routine ist ein besonderes UP das 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;
            Adresse 0x0004           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 nur für 5 Prozessortakten unterbrochen.&lt;br /&gt;
&lt;br /&gt;
                        0x0004           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 immer auf gleichen Stelle des Hauptprogramms 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; dient, genannt. Das ASM Programm,  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;
         u.s.w.&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;
         u.s.w&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;
         u.s.w. &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;
         u.s.w&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 detailiert das ganze Prozess der Erstellung eines ASM Programms 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 der Prozessor 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: [[#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;
 	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 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 in 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;
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 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;             ; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&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;
  	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 afgerufen 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 PORTs neu definieren und das UP &amp;quot;Warten&amp;quot; für z.B. 20 MHz Quarz anpassen:&lt;br /&gt;
&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			; prüfe, ob 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 LED1 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 LED1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
           bsf     _L2			; schalte LED2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte LED2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
           bsf     _L3			; schalte LED3 ein (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte LED3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
           bsf     _L4			; schalte LED4 ein (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte LED4 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, überspringe &amp;quot;goto Haupt&amp;quot;&lt;br /&gt;
           goto    Haupt		        ; Wenn nicht, springe zu Haupt&lt;br /&gt;
           bsf     _L4			; schalte LED4 ein (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L4			; schalte LED4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
           bsf     _L3			; schalte LED3 ein (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L3			; schalte LED3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
           bsf     _L2			; schalte LED2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L2			; schalte LED2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
           bsf     _L1			; schalte LED1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
           call    Warten		; warte&lt;br /&gt;
           bcf     _L1			; schalte LED1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&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 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 und ü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 und ü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 &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 aus der du afgerufen wurdest &lt;br /&gt;
 					; hier endet das gesamte ASM Programm &lt;br /&gt;
           end				; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
== Einbinden ==&lt;br /&gt;
&lt;br /&gt;
Die einfachste Möglichkeit die gewünschte Programme in ein neues Programm einzubinden ist, die 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ünschte 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.&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;
                                         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 eingebindenen Programmen keine &amp;quot;org&amp;quot; Direktiven gibt, dann  werden die weitere 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, u.s.w.) 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.&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 zur Programmierung. Jedes UP soll vor dem Übertragen in den Quellcode 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]] unersetzlich. Weil er durch Interrupt das Programm unterbricht und auf einem Display Registerinhalte während der Unterbrechung zeigt, 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 die Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; ein Codefragment als UP zu definieren erst wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck geeignet nur, wenn der Prozessor zum letzten Aufrufer 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 Parameter vor dem Aufruf des UPs in benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Zahlen von den Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Register durchzuführen (z.B. löschen) geeignet ist Anwendung von Schleifen 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;
 btfss 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 abefragt. 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;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, u.s.w.), 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;
= Mid-Range =&lt;br /&gt;
&lt;br /&gt;
Zu Mid-Range gehören alle PICs mit 14-bit langen Befehlen aus den Familien 12FXXX und 16FXXX. &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 b.z.w. 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. &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; oder &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;
&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 ANDLW. Dieser Befehl wird benutzt zum Löschen bestimmten Bits im Register ohne restlichen Bits zu beeinflüssen.&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 dem &amp;lt;tt&amp;gt;RETURN&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 (&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;) wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
:Der Befehl bewirkt das gleiche wie MOVLW 0 und darf im Programmen, die fur zukünftige Anwendung bei den PICs der serie 18F vorgesehen sind, nicht benutzt werden, da sie ihn nicht kennen.&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;
&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;
&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 IORLW. Dieser Befehl wird oft benutzt zum Setzen bestimmten Bits im Register ohne restlichen Bits zu beeinflüssen.&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 kopiert.&lt;br /&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;Temp&amp;quot; wurde mit &amp;quot;Temp   equ   0x20&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   Temp        ;ins W-Register wird die absolute Adresse 0x20 vom &amp;quot;Temp&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. Dieser Befehl wird 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 höheren 4 bit (bit7-bit4) mit den niedrigeren 4 bit (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;
&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;
: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;
&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 und wird zum Vergleichen zwei Register benutzt.&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;
&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) oder 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;
=== 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 Hifsregister. 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;
 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	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	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;
 CClr		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&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;
 		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 DAW)&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 Adressse 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;
                                   u.s.w.&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 fur Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adreesse &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 Programmteil misst eine Frequenz an TOCKI Pin und wurde für PIC16F870 geschrieben. &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;
Es fehlen UPs &amp;quot;Hex_Dec&amp;quot; [[#Hex Dec Wandlung|Hex Dec Wandlung]] und Ausgabe auf ein Display &amp;quot;DispFrq&amp;quot;. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts ausser warten auf ein Interrupt von Timer0 bzw. Timer1. Man kann die Marke &amp;quot;Main&amp;quot; weglassen und das HP als &amp;quot;goto $&amp;quot; formulieren.&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 Zähler der Frequenz wurde um ein Zähler aus zwei zusätzlichen Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TIMER0 ins A1 kopiert. Somit ergibt sich 32-bittiges Ergebniss, 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 biliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Es wird kein zusätzliches Register benötigt, da das &amp;quot;ATmp&amp;quot; und das &amp;quot;RTmp&amp;quot; die gleichen wie im UP &amp;quot;Hex_Dec&amp;quot; sind. Die Quarzfrequenz wurde gewählt, weil sie am nächsten der Temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist. Der PIC16F870 wurde nur wegen nötigen 19 I/O Pins für 6-stelligen 7-segment LCD Display LPH2673-1[[http://www.roboternetz.de/phpBB2/viewtopic.php?t=26005]] (ohne Kontroller) vom Pollin  angewendet. Mit einem üblichen 1x16 Zeichen LCD Matrixdisplay und anderen PICs wurde das Programm für Frequenzen bis zum 80 MHz mit einer Genauigkeit&lt;br /&gt;
+/- 4 Hz positiv getestet.&lt;br /&gt;
&lt;br /&gt;
Um die Frequenz mit Genauigkeit +/- 1Hz zu messen, muss die Messzeit 1 s von Timer1 erzeugt werden, das nur für Quarz bis 2,048 MHz möglich ist. 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 entsprechend geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Mit dem Quarz 7,3728 MHz wird hier die Messzeit 0,25 s genutzt und die gemessene Frequenz durch 4 multipliziert (mittels 2 Additionen), was die Auflösung von +/- 4 Hz ergibt.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Init&amp;quot; muss selbstverständlich für ein Matrixdisplay um Initialisierung des Displaykontrollers ergänzt werden.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F870&lt;br /&gt;
 	include &amp;quot;P16F870.inc&amp;quot;&lt;br /&gt;
 	__CONFIG	_CP_OFF &amp;amp; _DEBUG_OFF &amp;amp; _WRT_ENABLE_ON &amp;amp; _CPD_OFF &amp;amp; _LVP_OFF &amp;amp; _BODEN_OFF &amp;amp; &lt;br /&gt;
                         _PWRTE_ON &amp;amp; _WDT_OFF &amp;amp; _HS_OSC&lt;br /&gt;
 		ORG	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		goto	Main&lt;br /&gt;
 		ORG	0x0004			;ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE		;interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 übelaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;Timer0 interrupt flag löschen&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2&lt;br /&gt;
 		btfsc	STATUS,C&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                          ;wenn nicht, springe zurück zu Main  &lt;br /&gt;
 		bsf	STATUS,RP0		;stopp Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&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	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	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec&lt;br /&gt;
 		clrf	A3			;Register A löschen&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A0&lt;br /&gt;
 		call	CopyDC&lt;br /&gt;
 		call	AddDC			;gemessene Frequenz * 2&lt;br /&gt;
 		call	CopyDC&lt;br /&gt;
 		call	AddDC			;gemessene Frequenz * 4 = tatsächliche Frequenz&lt;br /&gt;
 		call	DispFrq                 ;eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	TMR0			;Timer0 löschen&lt;br /&gt;
 		movlw	0x34			;Timer1&lt;br /&gt;
 		movwf	T1CON			;konfigurieren&lt;br /&gt;
 		movlw	0x1F			;Timer1 laden (für 0,25 s)&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		clrf	TMR1L&lt;br /&gt;
 		bsf	STATUS,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	STATUS,RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		retfie				;erlaube interrupts und springe zurück zu Main&lt;br /&gt;
 CopyDC  	movf	D0,0&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movf	D1,0&lt;br /&gt;
 		movwf	C1&lt;br /&gt;
 		movf	D2,0&lt;br /&gt;
 		movwf	C2&lt;br /&gt;
 		movf	D3,0&lt;br /&gt;
 		movwf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Ports löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
                 clrf    PORTC&lt;br /&gt;
 		movlw	0x20			;RAM (20-7Fh) löschen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		btfss	FSR,7&lt;br /&gt;
 		goto	$-3     &lt;br /&gt;
 		clrf	ADCON0			;schalte ADC off&lt;br /&gt;
 		movlw	7			;sperre ADC&lt;br /&gt;
 		movwf	ADCON1			;und definiere RA0-7 als digitale I/Os&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		bsf	STATUS,RP0		;bank 1&lt;br /&gt;
 		clrf	TRISA			;alle PORTA,&lt;br /&gt;
 		clrf	TRISB			;alle PORTB,&lt;br /&gt;
                 clrf    TRISC                   ;und alle PORTC Pins als Ausgänge&lt;br /&gt;
 		movlw	0xE7			;Takt für Timer0 vom T0CKI Pin&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	STATUS,RP0		;Bank 0&lt;br /&gt;
 		clrf	TMR0			;Timer0 löschen&lt;br /&gt;
 		movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;(prescaler 8)&lt;br /&gt;
 		movlw	0x1F			;Timer1 laden (für 0,25 s)&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		clrf	TMR1L&lt;br /&gt;
 		bsf	STATUS,RP0              ;start Timer0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Eingang&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad aus und setzt, je nach Drehrichtug 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&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 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. Die Warteschleife &amp;quot;Delay&amp;quot; soll ca. 10ms sein.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTB eigelesen, die alle Bits ausser 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, b.z.w. 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 b.z.w. 02, 10 b.z.w. 13, 20 b.z.w. 23 oder 31 b.z.w. 32) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; b.z.w. &amp;quot;_Fdec&amp;quot; gesetzt. Anschliessend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detailierter 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;
=== Handy Display ===&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und Testprogram für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
&lt;br /&gt;
Hier werden einige Programme presentiert, die das ASM Programmieren erleichtern.&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;
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 PIC Miniterminal, 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;
Um das 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 20 MHz Quarz arbeitet. Für 4 MHz Quarz b.z.w. internen RC Oszillator muss die Interrupts-Anzahl in der ISR ( gezählt im &amp;quot;Int&amp;quot; Register) von 0x40 auf 0x10 reduziert werden, also &amp;quot;Int,4&amp;quot; anstatt &amp;quot;Int,6&amp;quot; prüfen.&lt;br /&gt;
&lt;br /&gt;
PIC RAM Monitor wird so konzipiert, das er in jedes ASM Programm eingebunden werden kann. Er braucht insgesamt 93 Speicherstellen im Programmspeicher, 9 Register im RAM und 2 I/O Portpins des PICs für den er benutzt wird.&lt;br /&gt;
&lt;br /&gt;
Der beobachtete ASM Programm darf, wegen ISR vom PIC RAM Monitor, erst ab der Adresse 0x0018 beginnen und nur bis zur Adresse 0x03AF gehen, da ab 0x03B0 im Programmspeicher der PIC RAM Monitor ist. Wenn ein benutzter PIC mehr Programmspeicher hat, kann der PIC RAM Monitor mit der &amp;quot;org&amp;quot; Direktive höher plaziert werden. Er belegt die 9 obersten Register im RAM (0x47 bis 0x4F), kann aber auch anderswo im RAM (z.B. in andere Bank) verlegt werden &lt;br /&gt;
&lt;br /&gt;
Um &amp;quot;Kollisionen&amp;quot; mit dem Programm, in das er eingebunden wird, zu vermeinden, fangen alle seine Marken mit &amp;quot;@&amp;quot; an.&lt;br /&gt;
&lt;br /&gt;
In dem beobachteten Programm müssen lediglich zwei Portpins, an die PIC Miniterminal angeschlossen wird, definiert und als Ausgang initialisiert werden. Ausserdem muss in die Initialisierung &amp;quot;@Init&amp;quot; eingefügt werden.&lt;br /&gt;
&lt;br /&gt;
Hier der Quellcode:&lt;br /&gt;
&lt;br /&gt;
 ;	PIC RAM Monitor&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;
 		ORG	0x0004		; ISR&lt;br /&gt;
 		bcf	INTCON,GIE	; interrupts sperren&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;
 		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,6		; prüfen, ob schon 64d. 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;
 		movf	@FSR,0		; FSR Register&lt;br /&gt;
 		movwf	FSR		; wiederherstellen&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;
 		retfie			; zurück ins Programm springen, interrupts erlauben &lt;br /&gt;
 		ORG     0x03B0&lt;br /&gt;
 @		movlw	0x20		; Anzeigen der Regisrerinhalte&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		; schicke Adresse der 1. Zeile&lt;br /&gt;
 		goto	@Cmd&lt;br /&gt;
 @2nd		movlw	0xC0		; schicke Adresse der 2. Zeile&lt;br /&gt;
 @Cmd       	movwf	@Tmp2		; schicke Befehl&lt;br /&gt;
 		bcf	STATUS,C&lt;br /&gt;
 		goto	@SendR&lt;br /&gt;
 @Val		movwf	@Tmp1		; schicke Zahl (0-FF)&lt;br /&gt;
 		swapf	@Tmp1,0&lt;br /&gt;
 		movwf	@Tmp4&lt;br /&gt;
 		call	@Num&lt;br /&gt;
 		movf	@Tmp1,0&lt;br /&gt;
 		movwf	@Tmp4&lt;br /&gt;
 @Num		movf	@Tmp4,0&lt;br /&gt;
 		andlw	0x0F		; schicke Ziffer (0-F)&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;
 @SendR  	movlw   9		; schicke ein Byte aus @Tmp2 + RS (9 Bits)&lt;br /&gt;
 		movwf   @Tmp3&lt;br /&gt;
 @SerSend	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	@SerSend&lt;br /&gt;
 		bcf	@DT		; setze Display&lt;br /&gt;
 		bsf	@DT		; Enable&lt;br /&gt;
 		movlw	0x30		; warte&lt;br /&gt;
 		movwf	@Tmp3&lt;br /&gt;
 		decfsz	@Tmp3,1&lt;br /&gt;
 		goto	$-1&lt;br /&gt;
 		bcf	@CK		; lösche&lt;br /&gt;
 		bcf	@DT		; Display&lt;br /&gt;
 		bsf	@DT		; Enable&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;
  	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	@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    0x0018&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 LED1 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 LED1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
           bsf     _L2               ; schalte LED2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
           call    Warten            ; warte&lt;br /&gt;
           bcf     _L2               ; schalte LED2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
           bsf     _L3               ; schalte LED3 ein (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
           call    Warten            ; warte&lt;br /&gt;
           bcf     _L3               ; schalte LED3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
           bsf     _L4               ; schalte LED4 ein (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
           call    Warten            ; warte&lt;br /&gt;
           bcf     _L4               ; schalte LED4 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 LED4 ein (setze den Pin 7 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
           call    Warten            ; warte&lt;br /&gt;
           bcf     _L4               ; schalte LED4 aus (setze den Pin 7 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
           bsf     _L3               ; schalte LED3 ein (setze den Pin 6 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
           call    Warten            ; warte&lt;br /&gt;
           bcf     _L3               ; schalte LED3 aus (setze den Pin 6 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
           bsf     _L2               ; schalte LED2 an (setze den Pin 5 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
           call    Warten            ; warte&lt;br /&gt;
           bcf     _L2               ; schalte LED2 aus (setze den Pin 5 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
           bsf     _L1               ; schalte LED1 an (setze den Pin 2 auf &amp;quot;1&amp;quot;)&lt;br /&gt;
           call    Warten            ; warte&lt;br /&gt;
           bcf     _L1               ; schalte LED1 aus (setze den Pin2 auf &amp;quot;0&amp;quot;)&lt;br /&gt;
           goto    Haupt             ; springe zu Haupt&lt;br /&gt;
 Warten    movlw   0x0A              ; schreibe &amp;quot;0x0A&amp;quot; (10d) 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 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 und ü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 und ü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 &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;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>Andy</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=11882</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=11882"/>
				<updated>2007-05-05T07:02:22Z</updated>
		
		<summary type="html">&lt;p&gt;Andy: /* PIC Miniterminal */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einladung zur Diskussion... =&lt;br /&gt;
&lt;br /&gt;
Es wird hier versucht die ASM Programmierung von PIC Mikrocontrollern möglichst kurz zu beschreiben.&lt;br /&gt;
&lt;br /&gt;
Damit der enstehende Artikel wirklich nützlich  wird, ist Ihre Mitwirkung nötig. Bitte schreiben Sie uns Ihre Meinung, was eventuell noch geändert (z.B. ergänzt) werden soll in diesem Thread:&lt;br /&gt;
&lt;br /&gt;
http://www.roboternetz.de/phpBB2/viewtopic.php?p=271211#271211&lt;br /&gt;
&lt;br /&gt;
Die Autoren bedanken sich im voraus für jeden Beitrag mit Vorschlägen !&lt;br /&gt;
&lt;br /&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 enhä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, u.s.w. 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 Mid-Range hat 14-bitige Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bitige 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 3 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. (INDF 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 ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 14-bittigen 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 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. Siehe: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von Mid-Range PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 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 Mid-Range Serie 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 (beim PIC 14 bit) 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 (fatch)        &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 kleinen eigenen Speicher, der weder zum Programmspeicher noch zum Datenspeicher gehört. Er besteht aus dem Programmzähler PC (programm counter) und dem Stapel (stack).&lt;br /&gt;
&lt;br /&gt;
In dem PC befindet sich die 13-Bittige Adresse des momentan ausfürbaren 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 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. Damit es möglich wäre, 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). &lt;br /&gt;
&lt;br /&gt;
Der Stapel kann aber nur 8 Adressen speichern, deswegen dürfen nur 8 nacheinander folgende &amp;quot;call&amp;quot; Befehle benutzt werden. Sonst findet der Prozessor nicht mehr zurück und in die &amp;quot;Nirvana&amp;quot; springt, was einen Absturz des Programms bedeutet.&lt;br /&gt;
&lt;br /&gt;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen Mid-Range 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 200 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 eigebundenen 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.&lt;br /&gt;
&lt;br /&gt;
Dank der integrierten oder an Portpins angeschlosenen Hardware und dem entsprechenden Program 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. 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 die wichtigsten 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 Texdatei 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) intalliert 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 Eischalten 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, u.s.w.). Bei diesen reicht es bereits Spannung anzulegen und sie laufen bereits.&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, u.s.w.) 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 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 MCLR Pin angeschlossene Hardware während der Programmierung zu schützen. &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 Versorgungspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF möglichts 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 vermeinden, 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 Program 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;
== 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össe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Grösse des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, u.s.w.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, u.s.w.).&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ägiges 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. PIC Trainer) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bischen 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 Program 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. Hautprogram (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 Programs 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, u.s.w. 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 eledigt 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 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 Texdatei 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 Assembler 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 dannn 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;
== Programmdurchlaufdiagramm ==&lt;br /&gt;
&lt;br /&gt;
Der Programdurchlaufdiagram (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 (ausser &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 Komputerprogramme 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 Program 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 eifach 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;
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; (Sleep) agewendet 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, endweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung. &lt;br /&gt;
&lt;br /&gt;
Als allgemeinnutziges 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 Hauptprogram 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 gesammten 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; gekenzeichnet 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. Ausserdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, u.s.w.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, u.s.w.) 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 Quelcode 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|Mausrad]]&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 Hauptprogram 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 fogender 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 der CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (ausser 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 der 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 Hauptprogram 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.&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 eigeschrieben:&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) aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&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 &lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Program 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 asführen kann, muss er vollständig und richtig 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 meistens 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 eingeschrieben 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ötigtenen Variablen die gewünschte 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                b.z.w.           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 alle Ports nacheinander gelöscht und 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   PORTA &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anchliessend werden für jeden Port die Werte in TRIS Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRIS 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 TRIS 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 TRASB 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 TRIS 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) b.z.w. nur als Eingang benutzt werden können. Bei Plannung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich ein bestimmter Pin für die geplannte 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, u.s.w.), 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 Herstellern 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;
                               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;
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;
                                        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 bestimmtes 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.&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 ) u.s.w. &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;
=== 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 dennen ist, dass die Sprungtabellen steuern den Programlauf 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 veschiedenen 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üch zum Aufrufer der Tabelle.&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, 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      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	dt      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	dt      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	dt      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	dt      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	dt      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   u.s.w.&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 0x00 enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator fur 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 Programms, 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, 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 im Programm verursachen.&lt;br /&gt;
&lt;br /&gt;
Um ein Interrupt auslösen zu können, muss er in UP &amp;quot;Init&amp;quot;, durch beschreiben nötigen Register (INTCON, PIR, u.s.w.) 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.&lt;br /&gt;
&lt;br /&gt;
==== Interrupt Service Routine ====&lt;br /&gt;
&lt;br /&gt;
Die Interrupt Service Routine ist ein besonderes UP das 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;
            Adresse 0x0004           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 nur für 5 Prozessortakten unterbrochen.&lt;br /&gt;
&lt;br /&gt;
                        0x0004           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 immer auf gleichen Stelle des Hauptprogramms 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; dient, genannt. Das ASM Programm,  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;
         u.s.w.&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;
         u.s.w&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;
         u.s.w. &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;
         u.s.w&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 detailiert das ganze Prozess der Erstellung eines ASM Programms 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 der Prozessor 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: [[#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;
 	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&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 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 in 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;
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 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;             ; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&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;
  	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 afgerufen wurdest &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
== Einbinden ==&lt;br /&gt;
&lt;br /&gt;
Die einfachste Möglichkeit die gewünschte Programme in ein neues Programm einzubinden ist, die 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ünschte 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.&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;
                                         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 eingebindenen Programmen keine &amp;quot;org&amp;quot; Direktiven gibt, dann  werden die weitere 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, u.s.w.) 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.&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 zur Programmierung. Jedes UP soll vor dem Übertragen in den Quellcode 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;
Wenn aus geprüften UPs erstelltes Programm nicht richtig funktioniert, müsste ein Fehler im PAD 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 die Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; ein Codefragment als UP zu definieren erst wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck geeignet nur, wenn der Prozessor zum letzten Aufrufer 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 Parameter vor dem Aufruf des UPs in benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Zahlen von den Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Register durchzuführen (z.B. löschen) geeignet ist Anwendung von Schleifen 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;
 btfss 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 abefragt. 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;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, u.s.w.), 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;
= Mid-Range =&lt;br /&gt;
&lt;br /&gt;
Zu Mid-Range gehören alle PICs mit 14-bit langen Befehlen aus den Familien 12FXXX und 16FXXX. &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 b.z.w. 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. &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; oder &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;
&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 ANDLW. Dieser Befehl wird benutzt zum Löschen bestimmten Bits im Register ohne restlichen Bits zu beeinflüssen.&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 dem &amp;lt;tt&amp;gt;RETURN&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 (&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;) wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
:Der Befehl bewirkt das gleiche wie MOVLW 0 und darf im Programmen, die fur zukünftige Anwendung bei den PICs der serie 18F vorgesehen sind, nicht benutzt werden, da sie ihn nicht kennen.&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;
&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;
&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 IORLW. Dieser Befehl wird oft benutzt zum Setzen bestimmten Bits im Register ohne restlichen Bits zu beeinflüssen.&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 kopiert.&lt;br /&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;Temp&amp;quot; wurde mit &amp;quot;Temp   equ   0x20&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   Temp        ;ins W-Register wird die absolute Adresse 0x20 vom &amp;quot;Temp&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. Dieser Befehl wird 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 höheren 4 bit (bit7-bit4) mit den niedrigeren 4 bit (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;
&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;
: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;
&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 und wird zum Vergleichen zwei Register benutzt.&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;
&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) oder 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;
=== 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 Hifsregister. 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;
 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	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	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;
 CClr		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&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;
 		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 DAW)&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 Adressse 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;
                                   u.s.w.&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 fur Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adreesse &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 Programmteil misst eine Frequenz an TOCKI Pin und wurde für PIC16F870 geschrieben. &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;
Es fehlen UPs &amp;quot;Hex_Dec&amp;quot; [[#Hex Dec Wandlung|Hex Dec Wandlung]] und Ausgabe auf ein Display &amp;quot;DispFrq&amp;quot;. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts ausser warten auf ein Interrupt von Timer0 bzw. Timer1. Man kann die Marke &amp;quot;Main&amp;quot; weglassen und das HP als &amp;quot;goto $&amp;quot; formulieren.&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 Zähler der Frequenz wurde um ein Zähler aus zwei zusätzlichen Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TIMER0 ins A1 kopiert. Somit ergibt sich 32-bittiges Ergebniss, 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 biliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Es wird kein zusätzliches Register benötigt, da das &amp;quot;ATmp&amp;quot; und das &amp;quot;RTmp&amp;quot; die gleichen wie im UP &amp;quot;Hex_Dec&amp;quot; sind. Die Quarzfrequenz wurde gewählt, weil sie am nächsten der Temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist. Der PIC16F870 wurde nur wegen nötigen 19 I/O Pins für 6-stelligen 7-segment LCD Display LPH2673-1[[http://www.roboternetz.de/phpBB2/viewtopic.php?t=26005]] (ohne Kontroller) vom Pollin  angewendet. Mit einem üblichen 1x16 Zeichen LCD Matrixdisplay und anderen PICs wurde das Programm für Frequenzen bis zum 80 MHz mit einer Genauigkeit&lt;br /&gt;
+/- 4 Hz positiv getestet.&lt;br /&gt;
&lt;br /&gt;
Um die Frequenz mit Genauigkeit +/- 1Hz zu messen, muss die Messzeit 1 s von Timer1 erzeugt werden, das nur für Quarz bis 2,048 MHz möglich ist. 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 entsprechend geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Mit dem Quarz 7,3728 MHz wird hier die Messzeit 0,25 s genutzt und die gemessene Frequenz durch 4 multipliziert (mittels 2 Additionen), was die Auflösung von +/- 4 Hz ergibt.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Init&amp;quot; muss selbstverständlich für ein Matrixdisplay um Initialisierung des Displaykontrollers ergänzt werden.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F870&lt;br /&gt;
 	include &amp;quot;P16F870.inc&amp;quot;&lt;br /&gt;
 	__CONFIG	_CP_OFF &amp;amp; _DEBUG_OFF &amp;amp; _WRT_ENABLE_ON &amp;amp; _CPD_OFF &amp;amp; _LVP_OFF &amp;amp; _BODEN_OFF &amp;amp; &lt;br /&gt;
                         _PWRTE_ON &amp;amp; _WDT_OFF &amp;amp; _HS_OSC&lt;br /&gt;
 		ORG	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		goto	Main&lt;br /&gt;
 		ORG	0x0004			;ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE		;interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 übelaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;Timer0 interrupt flag löschen&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2&lt;br /&gt;
 		btfsc	STATUS,C&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                          ;wenn nicht, springe zurück zu Main  &lt;br /&gt;
 		bsf	STATUS,RP0		;stopp Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&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	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	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec&lt;br /&gt;
 		clrf	A3			;Register A löschen&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A0&lt;br /&gt;
 		call	CopyDC&lt;br /&gt;
 		call	AddDC			;gemessene Frequenz * 2&lt;br /&gt;
 		call	CopyDC&lt;br /&gt;
 		call	AddDC			;gemessene Frequenz * 4 = tatsächliche Frequenz&lt;br /&gt;
 		call	DispFrq                 ;eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	TMR0			;Timer0 löschen&lt;br /&gt;
 		movlw	0x34			;Timer1&lt;br /&gt;
 		movwf	T1CON			;konfigurieren&lt;br /&gt;
 		movlw	0x1F			;Timer1 laden (für 0,25 s)&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		clrf	TMR1L&lt;br /&gt;
 		bsf	STATUS,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	STATUS,RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		retfie				;erlaube interrupts und springe zurück zu Main&lt;br /&gt;
 CopyDC  	movf	D0,0&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movf	D1,0&lt;br /&gt;
 		movwf	C1&lt;br /&gt;
 		movf	D2,0&lt;br /&gt;
 		movwf	C2&lt;br /&gt;
 		movf	D3,0&lt;br /&gt;
 		movwf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Ports löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
                 clrf    PORTC&lt;br /&gt;
 		movlw	0x20			;RAM (20-7Fh) löschen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		btfss	FSR,7&lt;br /&gt;
 		goto	$-3     &lt;br /&gt;
 		clrf	ADCON0			;schalte ADC off&lt;br /&gt;
 		movlw	7			;sperre ADC&lt;br /&gt;
 		movwf	ADCON1			;und definiere RA0-7 als digitale I/Os&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		bsf	STATUS,RP0		;bank 1&lt;br /&gt;
 		clrf	TRISA			;alle PORTA,&lt;br /&gt;
 		clrf	TRISB			;alle PORTB,&lt;br /&gt;
                 clrf    TRISC                   ;und alle PORTC Pins als Ausgänge&lt;br /&gt;
 		movlw	0xE7			;Takt für Timer0 vom T0CKI Pin&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	STATUS,RP0		;Bank 0&lt;br /&gt;
 		clrf	TMR0			;Timer0 löschen&lt;br /&gt;
 		movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;(prescaler 8)&lt;br /&gt;
 		movlw	0x1F			;Timer1 laden (für 0,25 s)&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		clrf	TMR1L&lt;br /&gt;
 		bsf	STATUS,RP0              ;start Timer0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Eingang&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad aus und setzt, je nach Drehrichtug 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&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 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. Die Warteschleife &amp;quot;Delay&amp;quot; soll ca. 10ms sein.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTB eigelesen, die alle Bits ausser 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, b.z.w. 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 b.z.w. 02, 10 b.z.w. 13, 20 b.z.w. 23 oder 31 b.z.w. 32) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; b.z.w. &amp;quot;_Fdec&amp;quot; gesetzt. Anschliessend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detailierter 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;
=== Handy Display ===&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und Testprogram für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
&lt;br /&gt;
Hier werden einige Programme presentiert, die das ASM Programmieren erleichtern.&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;
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;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>Andy</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=11881</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=11881"/>
				<updated>2007-05-05T07:00:14Z</updated>
		
		<summary type="html">&lt;p&gt;Andy: /* Hex Dec Wandlung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einladung zur Diskussion... =&lt;br /&gt;
&lt;br /&gt;
Es wird hier versucht die ASM Programmierung von PIC Mikrocontrollern möglichst kurz zu beschreiben.&lt;br /&gt;
&lt;br /&gt;
Damit der enstehende Artikel wirklich nützlich  wird, ist Ihre Mitwirkung nötig. Bitte schreiben Sie uns Ihre Meinung, was eventuell noch geändert (z.B. ergänzt) werden soll in diesem Thread:&lt;br /&gt;
&lt;br /&gt;
http://www.roboternetz.de/phpBB2/viewtopic.php?p=271211#271211&lt;br /&gt;
&lt;br /&gt;
Die Autoren bedanken sich im voraus für jeden Beitrag mit Vorschlägen !&lt;br /&gt;
&lt;br /&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 enhä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, u.s.w. 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 Mid-Range hat 14-bitige Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bitige 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 3 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. (INDF 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 ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 14-bittigen 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 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. Siehe: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von Mid-Range PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 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 Mid-Range Serie 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 (beim PIC 14 bit) 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 (fatch)        &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 kleinen eigenen Speicher, der weder zum Programmspeicher noch zum Datenspeicher gehört. Er besteht aus dem Programmzähler PC (programm counter) und dem Stapel (stack).&lt;br /&gt;
&lt;br /&gt;
In dem PC befindet sich die 13-Bittige Adresse des momentan ausfürbaren 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 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. Damit es möglich wäre, 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). &lt;br /&gt;
&lt;br /&gt;
Der Stapel kann aber nur 8 Adressen speichern, deswegen dürfen nur 8 nacheinander folgende &amp;quot;call&amp;quot; Befehle benutzt werden. Sonst findet der Prozessor nicht mehr zurück und in die &amp;quot;Nirvana&amp;quot; springt, was einen Absturz des Programms bedeutet.&lt;br /&gt;
&lt;br /&gt;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen Mid-Range 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 200 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 eigebundenen 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.&lt;br /&gt;
&lt;br /&gt;
Dank der integrierten oder an Portpins angeschlosenen Hardware und dem entsprechenden Program 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. 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 die wichtigsten 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 Texdatei 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) intalliert 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 Eischalten 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, u.s.w.). Bei diesen reicht es bereits Spannung anzulegen und sie laufen bereits.&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, u.s.w.) 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 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 MCLR Pin angeschlossene Hardware während der Programmierung zu schützen. &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 Versorgungspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF möglichts 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 vermeinden, 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 Program 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;
== 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össe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Grösse des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, u.s.w.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, u.s.w.).&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ägiges 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. PIC Trainer) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bischen 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 Program 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. Hautprogram (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 Programs 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, u.s.w. 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 eledigt 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 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 Texdatei 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 Assembler 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 dannn 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;
== Programmdurchlaufdiagramm ==&lt;br /&gt;
&lt;br /&gt;
Der Programdurchlaufdiagram (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 (ausser &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 Komputerprogramme 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 Program 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 eifach 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;
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; (Sleep) agewendet 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, endweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung. &lt;br /&gt;
&lt;br /&gt;
Als allgemeinnutziges 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 Hauptprogram 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 gesammten 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; gekenzeichnet 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. Ausserdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, u.s.w.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, u.s.w.) 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 Quelcode 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|Mausrad]]&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 Hauptprogram 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 fogender 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 der CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (ausser 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 der 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 Hauptprogram 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.&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 eigeschrieben:&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) aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&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 &lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Program 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 asführen kann, muss er vollständig und richtig 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 meistens 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 eingeschrieben 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ötigtenen Variablen die gewünschte 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                b.z.w.           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 alle Ports nacheinander gelöscht und 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   PORTA &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anchliessend werden für jeden Port die Werte in TRIS Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRIS 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 TRIS 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 TRASB 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 TRIS 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) b.z.w. nur als Eingang benutzt werden können. Bei Plannung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich ein bestimmter Pin für die geplannte 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, u.s.w.), 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 Herstellern 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;
                               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;
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;
                                        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 bestimmtes 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.&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 ) u.s.w. &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;
=== 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 dennen ist, dass die Sprungtabellen steuern den Programlauf 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 veschiedenen 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üch zum Aufrufer der Tabelle.&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, 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      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	dt      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	dt      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	dt      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	dt      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	dt      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   u.s.w.&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 0x00 enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator fur 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 Programms, 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, 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 im Programm verursachen.&lt;br /&gt;
&lt;br /&gt;
Um ein Interrupt auslösen zu können, muss er in UP &amp;quot;Init&amp;quot;, durch beschreiben nötigen Register (INTCON, PIR, u.s.w.) 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.&lt;br /&gt;
&lt;br /&gt;
==== Interrupt Service Routine ====&lt;br /&gt;
&lt;br /&gt;
Die Interrupt Service Routine ist ein besonderes UP das 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;
            Adresse 0x0004           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 nur für 5 Prozessortakten unterbrochen.&lt;br /&gt;
&lt;br /&gt;
                        0x0004           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 immer auf gleichen Stelle des Hauptprogramms 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; dient, genannt. Das ASM Programm,  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;
         u.s.w.&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;
         u.s.w&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;
         u.s.w. &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;
         u.s.w&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 detailiert das ganze Prozess der Erstellung eines ASM Programms 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 der Prozessor 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: [[#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;
 	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&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 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 in 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;
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 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;             ; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&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;
  	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 afgerufen wurdest &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
== Einbinden ==&lt;br /&gt;
&lt;br /&gt;
Die einfachste Möglichkeit die gewünschte Programme in ein neues Programm einzubinden ist, die 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ünschte 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.&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;
                                         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 eingebindenen Programmen keine &amp;quot;org&amp;quot; Direktiven gibt, dann  werden die weitere 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, u.s.w.) 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.&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 zur Programmierung. Jedes UP soll vor dem Übertragen in den Quellcode 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;
Wenn aus geprüften UPs erstelltes Programm nicht richtig funktioniert, müsste ein Fehler im PAD 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 die Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; ein Codefragment als UP zu definieren erst wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck geeignet nur, wenn der Prozessor zum letzten Aufrufer 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 Parameter vor dem Aufruf des UPs in benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Zahlen von den Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Register durchzuführen (z.B. löschen) geeignet ist Anwendung von Schleifen 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;
 btfss 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 abefragt. 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;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, u.s.w.), 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;
= Mid-Range =&lt;br /&gt;
&lt;br /&gt;
Zu Mid-Range gehören alle PICs mit 14-bit langen Befehlen aus den Familien 12FXXX und 16FXXX. &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 b.z.w. 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. &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; oder &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;
&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 ANDLW. Dieser Befehl wird benutzt zum Löschen bestimmten Bits im Register ohne restlichen Bits zu beeinflüssen.&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 dem &amp;lt;tt&amp;gt;RETURN&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 (&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;) wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
:Der Befehl bewirkt das gleiche wie MOVLW 0 und darf im Programmen, die fur zukünftige Anwendung bei den PICs der serie 18F vorgesehen sind, nicht benutzt werden, da sie ihn nicht kennen.&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;
&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;
&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 IORLW. Dieser Befehl wird oft benutzt zum Setzen bestimmten Bits im Register ohne restlichen Bits zu beeinflüssen.&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 kopiert.&lt;br /&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;Temp&amp;quot; wurde mit &amp;quot;Temp   equ   0x20&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   Temp        ;ins W-Register wird die absolute Adresse 0x20 vom &amp;quot;Temp&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. Dieser Befehl wird 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 höheren 4 bit (bit7-bit4) mit den niedrigeren 4 bit (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;
&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;
: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;
&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 und wird zum Vergleichen zwei Register benutzt.&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;
&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) oder 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;
=== 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 Hifsregister. 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;
 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	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	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;
 CClr		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&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;
 		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 DAW)&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 Adressse 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;
                                   u.s.w.&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 fur Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adreesse &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 Programmteil misst eine Frequenz an TOCKI Pin und wurde für PIC16F870 geschrieben. &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;
Es fehlen UPs &amp;quot;Hex_Dec&amp;quot; [[#Hex Dec Wandlung|Hex Dec Wandlung]] und Ausgabe auf ein Display &amp;quot;DispFrq&amp;quot;. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts ausser warten auf ein Interrupt von Timer0 bzw. Timer1. Man kann die Marke &amp;quot;Main&amp;quot; weglassen und das HP als &amp;quot;goto $&amp;quot; formulieren.&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 Zähler der Frequenz wurde um ein Zähler aus zwei zusätzlichen Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TIMER0 ins A1 kopiert. Somit ergibt sich 32-bittiges Ergebniss, 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 biliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Es wird kein zusätzliches Register benötigt, da das &amp;quot;ATmp&amp;quot; und das &amp;quot;RTmp&amp;quot; die gleichen wie im UP &amp;quot;Hex_Dec&amp;quot; sind. Die Quarzfrequenz wurde gewählt, weil sie am nächsten der Temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist. Der PIC16F870 wurde nur wegen nötigen 19 I/O Pins für 6-stelligen 7-segment LCD Display LPH2673-1[[http://www.roboternetz.de/phpBB2/viewtopic.php?t=26005]] (ohne Kontroller) vom Pollin  angewendet. Mit einem üblichen 1x16 Zeichen LCD Matrixdisplay und anderen PICs wurde das Programm für Frequenzen bis zum 80 MHz mit einer Genauigkeit&lt;br /&gt;
+/- 4 Hz positiv getestet.&lt;br /&gt;
&lt;br /&gt;
Um die Frequenz mit Genauigkeit +/- 1Hz zu messen, muss die Messzeit 1 s von Timer1 erzeugt werden, das nur für Quarz bis 2,048 MHz möglich ist. 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 entsprechend geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Mit dem Quarz 7,3728 MHz wird hier die Messzeit 0,25 s genutzt und die gemessene Frequenz durch 4 multipliziert (mittels 2 Additionen), was die Auflösung von +/- 4 Hz ergibt.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Init&amp;quot; muss selbstverständlich für ein Matrixdisplay um Initialisierung des Displaykontrollers ergänzt werden.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F870&lt;br /&gt;
 	include &amp;quot;P16F870.inc&amp;quot;&lt;br /&gt;
 	__CONFIG	_CP_OFF &amp;amp; _DEBUG_OFF &amp;amp; _WRT_ENABLE_ON &amp;amp; _CPD_OFF &amp;amp; _LVP_OFF &amp;amp; _BODEN_OFF &amp;amp; &lt;br /&gt;
                         _PWRTE_ON &amp;amp; _WDT_OFF &amp;amp; _HS_OSC&lt;br /&gt;
 		ORG	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		goto	Main&lt;br /&gt;
 		ORG	0x0004			;ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE		;interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 übelaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;Timer0 interrupt flag löschen&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2&lt;br /&gt;
 		btfsc	STATUS,C&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                          ;wenn nicht, springe zurück zu Main  &lt;br /&gt;
 		bsf	STATUS,RP0		;stopp Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&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	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	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec&lt;br /&gt;
 		clrf	A3			;Register A löschen&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A0&lt;br /&gt;
 		call	CopyDC&lt;br /&gt;
 		call	AddDC			;gemessene Frequenz * 2&lt;br /&gt;
 		call	CopyDC&lt;br /&gt;
 		call	AddDC			;gemessene Frequenz * 4 = tatsächliche Frequenz&lt;br /&gt;
 		call	DispFrq                 ;eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	TMR0			;Timer0 löschen&lt;br /&gt;
 		movlw	0x34			;Timer1&lt;br /&gt;
 		movwf	T1CON			;konfigurieren&lt;br /&gt;
 		movlw	0x1F			;Timer1 laden (für 0,25 s)&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		clrf	TMR1L&lt;br /&gt;
 		bsf	STATUS,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	STATUS,RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		retfie				;erlaube interrupts und springe zurück zu Main&lt;br /&gt;
 CopyDC  	movf	D0,0&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movf	D1,0&lt;br /&gt;
 		movwf	C1&lt;br /&gt;
 		movf	D2,0&lt;br /&gt;
 		movwf	C2&lt;br /&gt;
 		movf	D3,0&lt;br /&gt;
 		movwf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Ports löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
                 clrf    PORTC&lt;br /&gt;
 		movlw	0x20			;RAM (20-7Fh) löschen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		btfss	FSR,7&lt;br /&gt;
 		goto	$-3     &lt;br /&gt;
 		clrf	ADCON0			;schalte ADC off&lt;br /&gt;
 		movlw	7			;sperre ADC&lt;br /&gt;
 		movwf	ADCON1			;und definiere RA0-7 als digitale I/Os&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		bsf	STATUS,RP0		;bank 1&lt;br /&gt;
 		clrf	TRISA			;alle PORTA,&lt;br /&gt;
 		clrf	TRISB			;alle PORTB,&lt;br /&gt;
                 clrf    TRISC                   ;und alle PORTC Pins als Ausgänge&lt;br /&gt;
 		movlw	0xE7			;Takt für Timer0 vom T0CKI Pin&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	STATUS,RP0		;Bank 0&lt;br /&gt;
 		clrf	TMR0			;Timer0 löschen&lt;br /&gt;
 		movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;(prescaler 8)&lt;br /&gt;
 		movlw	0x1F			;Timer1 laden (für 0,25 s)&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		clrf	TMR1L&lt;br /&gt;
 		bsf	STATUS,RP0              ;start Timer0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Eingang&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad aus und setzt, je nach Drehrichtug 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&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 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. Die Warteschleife &amp;quot;Delay&amp;quot; soll ca. 10ms sein.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTB eigelesen, die alle Bits ausser 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, b.z.w. 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 b.z.w. 02, 10 b.z.w. 13, 20 b.z.w. 23 oder 31 b.z.w. 32) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; b.z.w. &amp;quot;_Fdec&amp;quot; gesetzt. Anschliessend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detailierter 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;
=== Handy Display ===&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und Testprogram für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
&lt;br /&gt;
Hier werden einige Programme presentiert, die das ASM Programmieren erleichtern.&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;
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 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;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>Andy</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=11879</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=11879"/>
				<updated>2007-05-05T06:39:13Z</updated>
		
		<summary type="html">&lt;p&gt;Andy: /* Speicher und Register */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einladung zur Diskussion... =&lt;br /&gt;
&lt;br /&gt;
Es wird hier versucht die ASM Programmierung von PIC Mikrocontrollern möglichst kurz zu beschreiben.&lt;br /&gt;
&lt;br /&gt;
Damit der enstehende Artikel wirklich nützlich  wird, ist Ihre Mitwirkung nötig. Bitte schreiben Sie uns Ihre Meinung, was eventuell noch geändert (z.B. ergänzt) werden soll in diesem Thread:&lt;br /&gt;
&lt;br /&gt;
http://www.roboternetz.de/phpBB2/viewtopic.php?p=271211#271211&lt;br /&gt;
&lt;br /&gt;
Die Autoren bedanken sich im voraus für jeden Beitrag mit Vorschlägen !&lt;br /&gt;
&lt;br /&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 enhä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, u.s.w. 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 Mid-Range hat 14-bitige Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bitige 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 3 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. (INDF 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 ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 14-bittigen 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 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. Siehe: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von Mid-Range PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 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 Mid-Range Serie 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 (beim PIC 14 bit) 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 (fatch)        &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 kleinen eigenen Speicher, der weder zum Programmspeicher noch zum Datenspeicher gehört. Er besteht aus dem Programmzähler PC (programm counter) und dem Stapel (stack).&lt;br /&gt;
&lt;br /&gt;
In dem PC befindet sich die 13-Bittige Adresse des momentan ausfürbaren 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 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. Damit es möglich wäre, 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). &lt;br /&gt;
&lt;br /&gt;
Der Stapel kann aber nur 8 Adressen speichern, deswegen dürfen nur 8 nacheinander folgende &amp;quot;call&amp;quot; Befehle benutzt werden. Sonst findet der Prozessor nicht mehr zurück und in die &amp;quot;Nirvana&amp;quot; springt, was einen Absturz des Programms bedeutet.&lt;br /&gt;
&lt;br /&gt;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen Mid-Range 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 200 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 eigebundenen 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.&lt;br /&gt;
&lt;br /&gt;
Dank der integrierten oder an Portpins angeschlosenen Hardware und dem entsprechenden Program 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. 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 die wichtigsten 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 Texdatei 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) intalliert 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 Eischalten 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, u.s.w.). Bei diesen reicht es bereits Spannung anzulegen und sie laufen bereits.&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, u.s.w.) 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 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 MCLR Pin angeschlossene Hardware während der Programmierung zu schützen. &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 Versorgungspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF möglichts 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 vermeinden, 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 Program 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;
== 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össe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Grösse des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, u.s.w.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, u.s.w.).&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ägiges 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. PIC Trainer) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bischen 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 Program 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. Hautprogram (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 Programs 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, u.s.w. 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 eledigt 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 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 Texdatei 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 Assembler 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 dannn 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;
== Programmdurchlaufdiagramm ==&lt;br /&gt;
&lt;br /&gt;
Der Programdurchlaufdiagram (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 (ausser &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 Komputerprogramme 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 Program 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 eifach 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;
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; (Sleep) agewendet 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, endweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung. &lt;br /&gt;
&lt;br /&gt;
Als allgemeinnutziges 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 Hauptprogram 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 gesammten 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; gekenzeichnet 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. Ausserdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, u.s.w.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, u.s.w.) 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 Quelcode 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|Mausrad]]&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 Hauptprogram 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 fogender 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 der CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (ausser 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 der 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 Hauptprogram 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.&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 eigeschrieben:&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) aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&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 &lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Program 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 asführen kann, muss er vollständig und richtig 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 meistens 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 eingeschrieben 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ötigtenen Variablen die gewünschte 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                b.z.w.           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 alle Ports nacheinander gelöscht und 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   PORTA &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anchliessend werden für jeden Port die Werte in TRIS Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRIS 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 TRIS 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 TRASB 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 TRIS 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) b.z.w. nur als Eingang benutzt werden können. Bei Plannung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich ein bestimmter Pin für die geplannte 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, u.s.w.), 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 Herstellern 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;
                               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;
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;
                                        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 bestimmtes 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.&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 ) u.s.w. &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;
=== 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 dennen ist, dass die Sprungtabellen steuern den Programlauf 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 veschiedenen 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üch zum Aufrufer der Tabelle.&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, 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      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	dt      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	dt      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	dt      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	dt      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	dt      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   u.s.w.&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 0x00 enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator fur 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 Programms, 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, 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 im Programm verursachen.&lt;br /&gt;
&lt;br /&gt;
Um ein Interrupt auslösen zu können, muss er in UP &amp;quot;Init&amp;quot;, durch beschreiben nötigen Register (INTCON, PIR, u.s.w.) 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.&lt;br /&gt;
&lt;br /&gt;
==== Interrupt Service Routine ====&lt;br /&gt;
&lt;br /&gt;
Die Interrupt Service Routine ist ein besonderes UP das 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;
            Adresse 0x0004           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 einfachste 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. &lt;br /&gt;
&lt;br /&gt;
                        0x0004           bcf     INTCON,GIE        ; Interrupts sperren&lt;br /&gt;
                                         bsf     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. &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; dient, genannt. Das ASM Programm,  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;
         u.s.w.&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;
         u.s.w&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;
         u.s.w. &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;
         u.s.w&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 detailiert das ganze Prozess der Erstellung eines ASM Programms 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 der Prozessor 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: [[#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;
 	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&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 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 in 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;
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 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;             ; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&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;
  	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 afgerufen wurdest &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
== Einbinden ==&lt;br /&gt;
&lt;br /&gt;
Die einfachste Möglichkeit die gewünschte Programme in ein neues Programm einzubinden ist, die 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ünschte 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.&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;
                                         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 eingebindenen Programmen keine &amp;quot;org&amp;quot; Direktiven gibt, dann  werden die weitere 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, u.s.w.) 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.&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 zur Programmierung. Jedes UP soll vor dem Übertragen in den Quellcode 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;
Wenn aus geprüften UPs erstelltes Programm nicht richtig funktioniert, müsste ein Fehler im PAD 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 die Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; ein Codefragment als UP zu definieren erst wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck geeignet nur, wenn der Prozessor zum letzten Aufrufer 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 Parameter vor dem Aufruf des UPs in benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Zahlen von den Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Register durchzuführen (z.B. löschen) geeignet ist Anwendung von Schleifen 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;
 btfss 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 abefragt. 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;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, u.s.w.), 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;
= Mid-Range =&lt;br /&gt;
&lt;br /&gt;
Zu Mid-Range gehören alle PICs mit 14-bit langen Befehlen aus den Familien 12FXXX und 16FXXX. &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 b.z.w. 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. &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; oder &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;
&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 ANDLW. Dieser Befehl wird benutzt zum Löschen bestimmten Bits im Register ohne restlichen Bits zu beeinflüssen.&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 dem &amp;lt;tt&amp;gt;RETURN&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 (&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;) wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
:Der Befehl bewirkt das gleiche wie MOVLW 0 und darf im Programmen, die fur zukünftige Anwendung bei den PICs der serie 18F vorgesehen sind, nicht benutzt werden, da sie ihn nicht kennen.&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;
&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;
&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 IORLW. Dieser Befehl wird oft benutzt zum Setzen bestimmten Bits im Register ohne restlichen Bits zu beeinflüssen.&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 kopiert.&lt;br /&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;Temp&amp;quot; wurde mit &amp;quot;Temp   equ   0x20&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   Temp        ;ins W-Register wird die absolute Adresse 0x20 vom &amp;quot;Temp&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. Dieser Befehl wird 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 höheren 4 bit (bit7-bit4) mit den niedrigeren 4 bit (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;
&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;
: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;
&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 und wird zum Vergleichen zwei Register benutzt.&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;
&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) oder 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;
=== 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 Hifsregister. 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; entschprechend 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 zum C addiert (&amp;quot;AddCB&amp;quot;) wird. Diese dec Zahl wird zum D Register addiert nur wenn entsprechender 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 Register 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, die max. hex Zahl darf  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;
 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	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	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;
 CClr		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&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;
 		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 DAW)&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 Adressse 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;
                                   u.s.w.&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 fur Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adreesse &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 Programmteil misst eine Frequenz an TOCKI Pin und wurde für PIC16F870 geschrieben. &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;
Es fehlen UPs &amp;quot;Hex_Dec&amp;quot; [[#Hex Dec Wandlung|Hex Dec Wandlung]] und Ausgabe auf ein Display &amp;quot;DispFrq&amp;quot;. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts ausser warten auf ein Interrupt von Timer0 bzw. Timer1. Man kann die Marke &amp;quot;Main&amp;quot; weglassen und das HP als &amp;quot;goto $&amp;quot; formulieren.&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 Zähler der Frequenz wurde um ein Zähler aus zwei zusätzlichen Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TIMER0 ins A1 kopiert. Somit ergibt sich 32-bittiges Ergebniss, 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 biliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Es wird kein zusätzliches Register benötigt, da das &amp;quot;ATmp&amp;quot; und das &amp;quot;RTmp&amp;quot; die gleichen wie im UP &amp;quot;Hex_Dec&amp;quot; sind. Die Quarzfrequenz wurde gewählt, weil sie am nächsten der Temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist. Der PIC16F870 wurde nur wegen nötigen 19 I/O Pins für 6-stelligen 7-segment LCD Display LPH2673-1[[http://www.roboternetz.de/phpBB2/viewtopic.php?t=26005]] (ohne Kontroller) vom Pollin  angewendet. Mit einem üblichen 1x16 Zeichen LCD Matrixdisplay und anderen PICs wurde das Programm für Frequenzen bis zum 80 MHz mit einer Genauigkeit&lt;br /&gt;
+/- 4 Hz positiv getestet.&lt;br /&gt;
&lt;br /&gt;
Um die Frequenz mit Genauigkeit +/- 1Hz zu messen, muss die Messzeit 1 s von Timer1 erzeugt werden, das nur für Quarz bis 2,048 MHz möglich ist. 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 entsprechend geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Mit dem Quarz 7,3728 MHz wird hier die Messzeit 0,25 s genutzt und die gemessene Frequenz durch 4 multipliziert (mittels 2 Additionen), was die Auflösung von +/- 4 Hz ergibt.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Init&amp;quot; muss selbstverständlich für ein Matrixdisplay um Initialisierung des Displaykontrollers ergänzt werden.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F870&lt;br /&gt;
 	include &amp;quot;P16F870.inc&amp;quot;&lt;br /&gt;
 	__CONFIG	_CP_OFF &amp;amp; _DEBUG_OFF &amp;amp; _WRT_ENABLE_ON &amp;amp; _CPD_OFF &amp;amp; _LVP_OFF &amp;amp; _BODEN_OFF &amp;amp; &lt;br /&gt;
                         _PWRTE_ON &amp;amp; _WDT_OFF &amp;amp; _HS_OSC&lt;br /&gt;
 		ORG	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		goto	Main&lt;br /&gt;
 		ORG	0x0004			;ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE		;interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 übelaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;Timer0 interrupt flag löschen&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2&lt;br /&gt;
 		btfsc	STATUS,C&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                          ;wenn nicht, springe zurück zu Main  &lt;br /&gt;
 		bsf	STATUS,RP0		;stopp Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&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	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	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec&lt;br /&gt;
 		clrf	A3			;Register A löschen&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A0&lt;br /&gt;
 		call	CopyDC&lt;br /&gt;
 		call	AddDC			;gemessene Frequenz * 2&lt;br /&gt;
 		call	CopyDC&lt;br /&gt;
 		call	AddDC			;gemessene Frequenz * 4 = tatsächliche Frequenz&lt;br /&gt;
 		call	DispFrq                 ;eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	TMR0			;Timer0 löschen&lt;br /&gt;
 		movlw	0x34			;Timer1&lt;br /&gt;
 		movwf	T1CON			;konfigurieren&lt;br /&gt;
 		movlw	0x1F			;Timer1 laden (für 0,25 s)&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		clrf	TMR1L&lt;br /&gt;
 		bsf	STATUS,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	STATUS,RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		retfie				;erlaube interrupts und springe zurück zu Main&lt;br /&gt;
 CopyDC  	movf	D0,0&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movf	D1,0&lt;br /&gt;
 		movwf	C1&lt;br /&gt;
 		movf	D2,0&lt;br /&gt;
 		movwf	C2&lt;br /&gt;
 		movf	D3,0&lt;br /&gt;
 		movwf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Ports löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
                 clrf    PORTC&lt;br /&gt;
 		movlw	0x20			;RAM (20-7Fh) löschen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		btfss	FSR,7&lt;br /&gt;
 		goto	$-3     &lt;br /&gt;
 		clrf	ADCON0			;schalte ADC off&lt;br /&gt;
 		movlw	7			;sperre ADC&lt;br /&gt;
 		movwf	ADCON1			;und definiere RA0-7 als digitale I/Os&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		bsf	STATUS,RP0		;bank 1&lt;br /&gt;
 		clrf	TRISA			;alle PORTA,&lt;br /&gt;
 		clrf	TRISB			;alle PORTB,&lt;br /&gt;
                 clrf    TRISC                   ;und alle PORTC Pins als Ausgänge&lt;br /&gt;
 		movlw	0xE7			;Takt für Timer0 vom T0CKI Pin&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	STATUS,RP0		;Bank 0&lt;br /&gt;
 		clrf	TMR0			;Timer0 löschen&lt;br /&gt;
 		movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;(prescaler 8)&lt;br /&gt;
 		movlw	0x1F			;Timer1 laden (für 0,25 s)&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		clrf	TMR1L&lt;br /&gt;
 		bsf	STATUS,RP0              ;start Timer0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Eingang&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad aus und setzt, je nach Drehrichtug 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&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 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. Die Warteschleife &amp;quot;Delay&amp;quot; soll ca. 10ms sein.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTB eigelesen, die alle Bits ausser 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, b.z.w. 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 b.z.w. 02, 10 b.z.w. 13, 20 b.z.w. 23 oder 31 b.z.w. 32) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; b.z.w. &amp;quot;_Fdec&amp;quot; gesetzt. Anschliessend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detailierter 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;
=== Handy Display ===&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und Testprogram für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
&lt;br /&gt;
Hier werden einige Programme presentiert, die das ASM Programmieren erleichtern.&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;
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 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;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>Andy</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=11878</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=11878"/>
				<updated>2007-05-05T06:25:19Z</updated>
		
		<summary type="html">&lt;p&gt;Andy: /* Bit, Byte, Nibble, Bin und Hex */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einladung zur Diskussion... =&lt;br /&gt;
&lt;br /&gt;
Es wird hier versucht die ASM Programmierung von PIC Mikrocontrollern möglichst kurz zu beschreiben.&lt;br /&gt;
&lt;br /&gt;
Damit der enstehende Artikel wirklich nützlich  wird, ist Ihre Mitwirkung nötig. Bitte schreiben Sie uns Ihre Meinung, was eventuell noch geändert (z.B. ergänzt) werden soll in diesem Thread:&lt;br /&gt;
&lt;br /&gt;
http://www.roboternetz.de/phpBB2/viewtopic.php?p=271211#271211&lt;br /&gt;
&lt;br /&gt;
Die Autoren bedanken sich im voraus für jeden Beitrag mit Vorschlägen !&lt;br /&gt;
&lt;br /&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 enhä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, u.s.w. 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 Mid-Range hat 14-bitige Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bitige 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. Jeder 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 3 sieht im PIC Register so aus: 00000011.&lt;br /&gt;
&lt;br /&gt;
Um ein Databyte 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 definierten 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 und der Wert aus &amp;quot;Temp&amp;quot; sich im &amp;quot;INDF&amp;quot; Register befindet. 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;, der sich jetzt&lt;br /&gt;
                         ;im &amp;quot;INDF&amp;quot; befindet, wird ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 14-bittigen 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 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. Siehe: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von Mid-Range PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 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 Mid-Range Serie 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 (beim PIC 14 bit) 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 (fatch)        &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 kleinen eigenen Speicher, der weder zum Programmspeicher noch zum Datenspeicher gehört. Er besteht aus dem Programmzähler PC (programm counter) und dem Stapel (stack).&lt;br /&gt;
&lt;br /&gt;
In dem PC befindet sich die 13-Bittige Adresse des momentan ausfürbaren 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 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. Damit es möglich wäre, 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). &lt;br /&gt;
&lt;br /&gt;
Der Stapel kann aber nur 8 Adressen speichern, deswegen dürfen nur 8 nacheinander folgende &amp;quot;call&amp;quot; Befehle benutzt werden. Sonst findet der Prozessor nicht mehr zurück und in die &amp;quot;Nirvana&amp;quot; springt, was einen Absturz des Programms bedeutet.&lt;br /&gt;
&lt;br /&gt;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen Mid-Range 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 200 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 eigebundenen 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.&lt;br /&gt;
&lt;br /&gt;
Dank der integrierten oder an Portpins angeschlosenen Hardware und dem entsprechenden Program 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. 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 die wichtigsten 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 Texdatei 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) intalliert 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 Eischalten 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, u.s.w.). Bei diesen reicht es bereits Spannung anzulegen und sie laufen bereits.&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, u.s.w.) 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 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 MCLR Pin angeschlossene Hardware während der Programmierung zu schützen. &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 Versorgungspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF möglichts 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 vermeinden, 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 Program 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;
== 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össe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Grösse des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, u.s.w.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, u.s.w.).&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ägiges 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. PIC Trainer) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bischen 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 Program 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. Hautprogram (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 Programs 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, u.s.w. 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 eledigt 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 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 Texdatei 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 Assembler 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 dannn 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;
== Programmdurchlaufdiagramm ==&lt;br /&gt;
&lt;br /&gt;
Der Programdurchlaufdiagram (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 (ausser &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 Komputerprogramme 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 Program 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 eifach 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;
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; (Sleep) agewendet 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, endweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung. &lt;br /&gt;
&lt;br /&gt;
Als allgemeinnutziges 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 Hauptprogram 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 gesammten 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; gekenzeichnet 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. Ausserdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, u.s.w.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, u.s.w.) 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 Quelcode 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|Mausrad]]&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 Hauptprogram 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 fogender 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 der CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (ausser 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 der 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 Hauptprogram 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.&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 eigeschrieben:&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) aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&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 &lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Program 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 asführen kann, muss er vollständig und richtig 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 meistens 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 eingeschrieben 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ötigtenen Variablen die gewünschte 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                b.z.w.           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 alle Ports nacheinander gelöscht und 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   PORTA &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anchliessend werden für jeden Port die Werte in TRIS Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRIS 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 TRIS 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 TRASB 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 TRIS 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) b.z.w. nur als Eingang benutzt werden können. Bei Plannung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich ein bestimmter Pin für die geplannte 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, u.s.w.), 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 Herstellern 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;
                               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;
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;
                                        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 bestimmtes 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.&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 ) u.s.w. &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;
=== 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 dennen ist, dass die Sprungtabellen steuern den Programlauf 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 veschiedenen 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üch zum Aufrufer der Tabelle.&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, 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      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	dt      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	dt      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	dt      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	dt      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	dt      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   u.s.w.&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 0x00 enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator fur 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 Programms, 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, 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 im Programm verursachen.&lt;br /&gt;
&lt;br /&gt;
Um ein Interrupt auslösen zu können, muss er in UP &amp;quot;Init&amp;quot;, durch beschreiben nötigen Register (INTCON, PIR, u.s.w.) 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.&lt;br /&gt;
&lt;br /&gt;
==== Interrupt Service Routine ====&lt;br /&gt;
&lt;br /&gt;
Die Interrupt Service Routine ist ein besonderes UP das 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;
            Adresse 0x0004           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 einfachste 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. &lt;br /&gt;
&lt;br /&gt;
                        0x0004           bcf     INTCON,GIE        ; Interrupts sperren&lt;br /&gt;
                                         bsf     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. &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; dient, genannt. Das ASM Programm,  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;
         u.s.w.&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;
         u.s.w&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;
         u.s.w. &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;
         u.s.w&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 detailiert das ganze Prozess der Erstellung eines ASM Programms 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 der Prozessor 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: [[#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;
 	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&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 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 in 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;
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 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;             ; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&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;
  	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 afgerufen wurdest &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
== Einbinden ==&lt;br /&gt;
&lt;br /&gt;
Die einfachste Möglichkeit die gewünschte Programme in ein neues Programm einzubinden ist, die 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ünschte 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.&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;
                                         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 eingebindenen Programmen keine &amp;quot;org&amp;quot; Direktiven gibt, dann  werden die weitere 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, u.s.w.) 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.&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 zur Programmierung. Jedes UP soll vor dem Übertragen in den Quellcode 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;
Wenn aus geprüften UPs erstelltes Programm nicht richtig funktioniert, müsste ein Fehler im PAD 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 die Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; ein Codefragment als UP zu definieren erst wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck geeignet nur, wenn der Prozessor zum letzten Aufrufer 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 Parameter vor dem Aufruf des UPs in benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Zahlen von den Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Register durchzuführen (z.B. löschen) geeignet ist Anwendung von Schleifen 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;
 btfss 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 abefragt. 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;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, u.s.w.), 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;
= Mid-Range =&lt;br /&gt;
&lt;br /&gt;
Zu Mid-Range gehören alle PICs mit 14-bit langen Befehlen aus den Familien 12FXXX und 16FXXX. &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 b.z.w. 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. &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; oder &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;
&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 ANDLW. Dieser Befehl wird benutzt zum Löschen bestimmten Bits im Register ohne restlichen Bits zu beeinflüssen.&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 dem &amp;lt;tt&amp;gt;RETURN&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 (&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;) wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
:Der Befehl bewirkt das gleiche wie MOVLW 0 und darf im Programmen, die fur zukünftige Anwendung bei den PICs der serie 18F vorgesehen sind, nicht benutzt werden, da sie ihn nicht kennen.&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;
&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;
&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 IORLW. Dieser Befehl wird oft benutzt zum Setzen bestimmten Bits im Register ohne restlichen Bits zu beeinflüssen.&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 kopiert.&lt;br /&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;Temp&amp;quot; wurde mit &amp;quot;Temp   equ   0x20&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   Temp        ;ins W-Register wird die absolute Adresse 0x20 vom &amp;quot;Temp&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. Dieser Befehl wird 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 höheren 4 bit (bit7-bit4) mit den niedrigeren 4 bit (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;
&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;
: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;
&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 und wird zum Vergleichen zwei Register benutzt.&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;
&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) oder 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;
=== 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 Hifsregister. 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; entschprechend 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 zum C addiert (&amp;quot;AddCB&amp;quot;) wird. Diese dec Zahl wird zum D Register addiert nur wenn entsprechender 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 Register 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, die max. hex Zahl darf  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;
 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	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	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;
 CClr		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&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;
 		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 DAW)&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 Adressse 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;
                                   u.s.w.&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 fur Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adreesse &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 Programmteil misst eine Frequenz an TOCKI Pin und wurde für PIC16F870 geschrieben. &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;
Es fehlen UPs &amp;quot;Hex_Dec&amp;quot; [[#Hex Dec Wandlung|Hex Dec Wandlung]] und Ausgabe auf ein Display &amp;quot;DispFrq&amp;quot;. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts ausser warten auf ein Interrupt von Timer0 bzw. Timer1. Man kann die Marke &amp;quot;Main&amp;quot; weglassen und das HP als &amp;quot;goto $&amp;quot; formulieren.&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 Zähler der Frequenz wurde um ein Zähler aus zwei zusätzlichen Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TIMER0 ins A1 kopiert. Somit ergibt sich 32-bittiges Ergebniss, 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 biliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Es wird kein zusätzliches Register benötigt, da das &amp;quot;ATmp&amp;quot; und das &amp;quot;RTmp&amp;quot; die gleichen wie im UP &amp;quot;Hex_Dec&amp;quot; sind. Die Quarzfrequenz wurde gewählt, weil sie am nächsten der Temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist. Der PIC16F870 wurde nur wegen nötigen 19 I/O Pins für 6-stelligen 7-segment LCD Display LPH2673-1[[http://www.roboternetz.de/phpBB2/viewtopic.php?t=26005]] (ohne Kontroller) vom Pollin  angewendet. Mit einem üblichen 1x16 Zeichen LCD Matrixdisplay und anderen PICs wurde das Programm für Frequenzen bis zum 80 MHz mit einer Genauigkeit&lt;br /&gt;
+/- 4 Hz positiv getestet.&lt;br /&gt;
&lt;br /&gt;
Um die Frequenz mit Genauigkeit +/- 1Hz zu messen, muss die Messzeit 1 s von Timer1 erzeugt werden, das nur für Quarz bis 2,048 MHz möglich ist. 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 entsprechend geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Mit dem Quarz 7,3728 MHz wird hier die Messzeit 0,25 s genutzt und die gemessene Frequenz durch 4 multipliziert (mittels 2 Additionen), was die Auflösung von +/- 4 Hz ergibt.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Init&amp;quot; muss selbstverständlich für ein Matrixdisplay um Initialisierung des Displaykontrollers ergänzt werden.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F870&lt;br /&gt;
 	include &amp;quot;P16F870.inc&amp;quot;&lt;br /&gt;
 	__CONFIG	_CP_OFF &amp;amp; _DEBUG_OFF &amp;amp; _WRT_ENABLE_ON &amp;amp; _CPD_OFF &amp;amp; _LVP_OFF &amp;amp; _BODEN_OFF &amp;amp; &lt;br /&gt;
                         _PWRTE_ON &amp;amp; _WDT_OFF &amp;amp; _HS_OSC&lt;br /&gt;
 		ORG	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		goto	Main&lt;br /&gt;
 		ORG	0x0004			;ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE		;interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 übelaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;Timer0 interrupt flag löschen&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2&lt;br /&gt;
 		btfsc	STATUS,C&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                          ;wenn nicht, springe zurück zu Main  &lt;br /&gt;
 		bsf	STATUS,RP0		;stopp Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&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	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	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec&lt;br /&gt;
 		clrf	A3			;Register A löschen&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A0&lt;br /&gt;
 		call	CopyDC&lt;br /&gt;
 		call	AddDC			;gemessene Frequenz * 2&lt;br /&gt;
 		call	CopyDC&lt;br /&gt;
 		call	AddDC			;gemessene Frequenz * 4 = tatsächliche Frequenz&lt;br /&gt;
 		call	DispFrq                 ;eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	TMR0			;Timer0 löschen&lt;br /&gt;
 		movlw	0x34			;Timer1&lt;br /&gt;
 		movwf	T1CON			;konfigurieren&lt;br /&gt;
 		movlw	0x1F			;Timer1 laden (für 0,25 s)&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		clrf	TMR1L&lt;br /&gt;
 		bsf	STATUS,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	STATUS,RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		retfie				;erlaube interrupts und springe zurück zu Main&lt;br /&gt;
 CopyDC  	movf	D0,0&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movf	D1,0&lt;br /&gt;
 		movwf	C1&lt;br /&gt;
 		movf	D2,0&lt;br /&gt;
 		movwf	C2&lt;br /&gt;
 		movf	D3,0&lt;br /&gt;
 		movwf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Ports löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
                 clrf    PORTC&lt;br /&gt;
 		movlw	0x20			;RAM (20-7Fh) löschen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		btfss	FSR,7&lt;br /&gt;
 		goto	$-3     &lt;br /&gt;
 		clrf	ADCON0			;schalte ADC off&lt;br /&gt;
 		movlw	7			;sperre ADC&lt;br /&gt;
 		movwf	ADCON1			;und definiere RA0-7 als digitale I/Os&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		bsf	STATUS,RP0		;bank 1&lt;br /&gt;
 		clrf	TRISA			;alle PORTA,&lt;br /&gt;
 		clrf	TRISB			;alle PORTB,&lt;br /&gt;
                 clrf    TRISC                   ;und alle PORTC Pins als Ausgänge&lt;br /&gt;
 		movlw	0xE7			;Takt für Timer0 vom T0CKI Pin&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	STATUS,RP0		;Bank 0&lt;br /&gt;
 		clrf	TMR0			;Timer0 löschen&lt;br /&gt;
 		movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;(prescaler 8)&lt;br /&gt;
 		movlw	0x1F			;Timer1 laden (für 0,25 s)&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		clrf	TMR1L&lt;br /&gt;
 		bsf	STATUS,RP0              ;start Timer0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Eingang&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad aus und setzt, je nach Drehrichtug 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&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 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. Die Warteschleife &amp;quot;Delay&amp;quot; soll ca. 10ms sein.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTB eigelesen, die alle Bits ausser 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, b.z.w. 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 b.z.w. 02, 10 b.z.w. 13, 20 b.z.w. 23 oder 31 b.z.w. 32) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; b.z.w. &amp;quot;_Fdec&amp;quot; gesetzt. Anschliessend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detailierter 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;
=== Handy Display ===&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und Testprogram für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
&lt;br /&gt;
Hier werden einige Programme presentiert, die das ASM Programmieren erleichtern.&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;
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 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;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>Andy</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=11877</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=11877"/>
				<updated>2007-05-05T06:24:23Z</updated>
		
		<summary type="html">&lt;p&gt;Andy: /* Bit, Byte, Nibble, Bin und Hex */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einladung zur Diskussion... =&lt;br /&gt;
&lt;br /&gt;
Es wird hier versucht die ASM Programmierung von PIC Mikrocontrollern möglichst kurz zu beschreiben.&lt;br /&gt;
&lt;br /&gt;
Damit der enstehende Artikel wirklich nützlich  wird, ist Ihre Mitwirkung nötig. Bitte schreiben Sie uns Ihre Meinung, was eventuell noch geändert (z.B. ergänzt) werden soll in diesem Thread:&lt;br /&gt;
&lt;br /&gt;
http://www.roboternetz.de/phpBB2/viewtopic.php?p=271211#271211&lt;br /&gt;
&lt;br /&gt;
Die Autoren bedanken sich im voraus für jeden Beitrag mit Vorschlägen !&lt;br /&gt;
&lt;br /&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 enhä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 jeder 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, u.s.w. 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 Mid-Range hat 14-bitige Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bitige 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. Jeder 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 3 sieht im PIC Register so aus: 00000011.&lt;br /&gt;
&lt;br /&gt;
Um ein Databyte 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 definierten 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 und der Wert aus &amp;quot;Temp&amp;quot; sich im &amp;quot;INDF&amp;quot; Register befindet. 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;, der sich jetzt&lt;br /&gt;
                         ;im &amp;quot;INDF&amp;quot; befindet, wird ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 14-bittigen 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 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. Siehe: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von Mid-Range PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 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 Mid-Range Serie 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 (beim PIC 14 bit) 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 (fatch)        &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 kleinen eigenen Speicher, der weder zum Programmspeicher noch zum Datenspeicher gehört. Er besteht aus dem Programmzähler PC (programm counter) und dem Stapel (stack).&lt;br /&gt;
&lt;br /&gt;
In dem PC befindet sich die 13-Bittige Adresse des momentan ausfürbaren 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 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. Damit es möglich wäre, 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). &lt;br /&gt;
&lt;br /&gt;
Der Stapel kann aber nur 8 Adressen speichern, deswegen dürfen nur 8 nacheinander folgende &amp;quot;call&amp;quot; Befehle benutzt werden. Sonst findet der Prozessor nicht mehr zurück und in die &amp;quot;Nirvana&amp;quot; springt, was einen Absturz des Programms bedeutet.&lt;br /&gt;
&lt;br /&gt;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen Mid-Range 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 200 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 eigebundenen 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.&lt;br /&gt;
&lt;br /&gt;
Dank der integrierten oder an Portpins angeschlosenen Hardware und dem entsprechenden Program 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. 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 die wichtigsten 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 Texdatei 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) intalliert 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 Eischalten 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, u.s.w.). Bei diesen reicht es bereits Spannung anzulegen und sie laufen bereits.&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, u.s.w.) 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 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 MCLR Pin angeschlossene Hardware während der Programmierung zu schützen. &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 Versorgungspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF möglichts 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 vermeinden, 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 Program 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;
== 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össe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Grösse des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, u.s.w.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, u.s.w.).&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ägiges 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. PIC Trainer) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bischen 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 Program 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. Hautprogram (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 Programs 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, u.s.w. 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 eledigt 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 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 Texdatei 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 Assembler 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 dannn 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;
== Programmdurchlaufdiagramm ==&lt;br /&gt;
&lt;br /&gt;
Der Programdurchlaufdiagram (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 (ausser &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 Komputerprogramme 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 Program 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 eifach 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;
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; (Sleep) agewendet 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, endweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung. &lt;br /&gt;
&lt;br /&gt;
Als allgemeinnutziges 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 Hauptprogram 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 gesammten 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; gekenzeichnet 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. Ausserdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, u.s.w.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, u.s.w.) 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 Quelcode 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|Mausrad]]&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 Hauptprogram 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 fogender 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 der CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (ausser 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 der 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 Hauptprogram 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.&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 eigeschrieben:&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) aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&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 &lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Program 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 asführen kann, muss er vollständig und richtig 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 meistens 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 eingeschrieben 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ötigtenen Variablen die gewünschte 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                b.z.w.           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 alle Ports nacheinander gelöscht und 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   PORTA &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anchliessend werden für jeden Port die Werte in TRIS Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRIS 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 TRIS 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 TRASB 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 TRIS 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) b.z.w. nur als Eingang benutzt werden können. Bei Plannung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich ein bestimmter Pin für die geplannte 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, u.s.w.), 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 Herstellern 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;
                               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;
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;
                                        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 bestimmtes 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.&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 ) u.s.w. &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;
=== 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 dennen ist, dass die Sprungtabellen steuern den Programlauf 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 veschiedenen 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üch zum Aufrufer der Tabelle.&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, 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      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	dt      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	dt      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	dt      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	dt      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	dt      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   u.s.w.&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 0x00 enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator fur 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 Programms, 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, 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 im Programm verursachen.&lt;br /&gt;
&lt;br /&gt;
Um ein Interrupt auslösen zu können, muss er in UP &amp;quot;Init&amp;quot;, durch beschreiben nötigen Register (INTCON, PIR, u.s.w.) 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.&lt;br /&gt;
&lt;br /&gt;
==== Interrupt Service Routine ====&lt;br /&gt;
&lt;br /&gt;
Die Interrupt Service Routine ist ein besonderes UP das 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;
            Adresse 0x0004           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 einfachste 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. &lt;br /&gt;
&lt;br /&gt;
                        0x0004           bcf     INTCON,GIE        ; Interrupts sperren&lt;br /&gt;
                                         bsf     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. &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; dient, genannt. Das ASM Programm,  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;
         u.s.w.&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;
         u.s.w&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;
         u.s.w. &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;
         u.s.w&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 detailiert das ganze Prozess der Erstellung eines ASM Programms 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 der Prozessor 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: [[#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;
 	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&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 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 in 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;
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 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;             ; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&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;
  	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 afgerufen wurdest &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&lt;br /&gt;
&lt;br /&gt;
== Einbinden ==&lt;br /&gt;
&lt;br /&gt;
Die einfachste Möglichkeit die gewünschte Programme in ein neues Programm einzubinden ist, die 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ünschte 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.&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;
                                         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 eingebindenen Programmen keine &amp;quot;org&amp;quot; Direktiven gibt, dann  werden die weitere 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, u.s.w.) 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.&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 zur Programmierung. Jedes UP soll vor dem Übertragen in den Quellcode 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;
Wenn aus geprüften UPs erstelltes Programm nicht richtig funktioniert, müsste ein Fehler im PAD 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 die Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; ein Codefragment als UP zu definieren erst wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck geeignet nur, wenn der Prozessor zum letzten Aufrufer 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 Parameter vor dem Aufruf des UPs in benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Zahlen von den Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Register durchzuführen (z.B. löschen) geeignet ist Anwendung von Schleifen 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;
 btfss 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 abefragt. 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;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, u.s.w.), 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;
= Mid-Range =&lt;br /&gt;
&lt;br /&gt;
Zu Mid-Range gehören alle PICs mit 14-bit langen Befehlen aus den Familien 12FXXX und 16FXXX. &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 b.z.w. 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. &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; oder &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;
&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 ANDLW. Dieser Befehl wird benutzt zum Löschen bestimmten Bits im Register ohne restlichen Bits zu beeinflüssen.&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 dem &amp;lt;tt&amp;gt;RETURN&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 (&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;) wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
:Der Befehl bewirkt das gleiche wie MOVLW 0 und darf im Programmen, die fur zukünftige Anwendung bei den PICs der serie 18F vorgesehen sind, nicht benutzt werden, da sie ihn nicht kennen.&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;
&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;
&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 IORLW. Dieser Befehl wird oft benutzt zum Setzen bestimmten Bits im Register ohne restlichen Bits zu beeinflüssen.&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 kopiert.&lt;br /&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;Temp&amp;quot; wurde mit &amp;quot;Temp   equ   0x20&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   Temp        ;ins W-Register wird die absolute Adresse 0x20 vom &amp;quot;Temp&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. Dieser Befehl wird 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 höheren 4 bit (bit7-bit4) mit den niedrigeren 4 bit (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;
&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;
: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;
&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 und wird zum Vergleichen zwei Register benutzt.&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;
&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) oder 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;
=== 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 Hifsregister. 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; entschprechend 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 zum C addiert (&amp;quot;AddCB&amp;quot;) wird. Diese dec Zahl wird zum D Register addiert nur wenn entsprechender 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 Register 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, die max. hex Zahl darf  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;
 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	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	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;
 CClr		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&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;
 		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 DAW)&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 Adressse 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;
                                   u.s.w.&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 fur Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adreesse &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 Programmteil misst eine Frequenz an TOCKI Pin und wurde für PIC16F870 geschrieben. &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;
Es fehlen UPs &amp;quot;Hex_Dec&amp;quot; [[#Hex Dec Wandlung|Hex Dec Wandlung]] und Ausgabe auf ein Display &amp;quot;DispFrq&amp;quot;. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts ausser warten auf ein Interrupt von Timer0 bzw. Timer1. Man kann die Marke &amp;quot;Main&amp;quot; weglassen und das HP als &amp;quot;goto $&amp;quot; formulieren.&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 Zähler der Frequenz wurde um ein Zähler aus zwei zusätzlichen Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TIMER0 ins A1 kopiert. Somit ergibt sich 32-bittiges Ergebniss, 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 biliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Es wird kein zusätzliches Register benötigt, da das &amp;quot;ATmp&amp;quot; und das &amp;quot;RTmp&amp;quot; die gleichen wie im UP &amp;quot;Hex_Dec&amp;quot; sind. Die Quarzfrequenz wurde gewählt, weil sie am nächsten der Temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist. Der PIC16F870 wurde nur wegen nötigen 19 I/O Pins für 6-stelligen 7-segment LCD Display LPH2673-1[[http://www.roboternetz.de/phpBB2/viewtopic.php?t=26005]] (ohne Kontroller) vom Pollin  angewendet. Mit einem üblichen 1x16 Zeichen LCD Matrixdisplay und anderen PICs wurde das Programm für Frequenzen bis zum 80 MHz mit einer Genauigkeit&lt;br /&gt;
+/- 4 Hz positiv getestet.&lt;br /&gt;
&lt;br /&gt;
Um die Frequenz mit Genauigkeit +/- 1Hz zu messen, muss die Messzeit 1 s von Timer1 erzeugt werden, das nur für Quarz bis 2,048 MHz möglich ist. 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 entsprechend geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Mit dem Quarz 7,3728 MHz wird hier die Messzeit 0,25 s genutzt und die gemessene Frequenz durch 4 multipliziert (mittels 2 Additionen), was die Auflösung von +/- 4 Hz ergibt.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Init&amp;quot; muss selbstverständlich für ein Matrixdisplay um Initialisierung des Displaykontrollers ergänzt werden.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F870&lt;br /&gt;
 	include &amp;quot;P16F870.inc&amp;quot;&lt;br /&gt;
 	__CONFIG	_CP_OFF &amp;amp; _DEBUG_OFF &amp;amp; _WRT_ENABLE_ON &amp;amp; _CPD_OFF &amp;amp; _LVP_OFF &amp;amp; _BODEN_OFF &amp;amp; &lt;br /&gt;
                         _PWRTE_ON &amp;amp; _WDT_OFF &amp;amp; _HS_OSC&lt;br /&gt;
 		ORG	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		goto	Main&lt;br /&gt;
 		ORG	0x0004			;ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE		;interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 übelaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;Timer0 interrupt flag löschen&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2&lt;br /&gt;
 		btfsc	STATUS,C&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                          ;wenn nicht, springe zurück zu Main  &lt;br /&gt;
 		bsf	STATUS,RP0		;stopp Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&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	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	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec&lt;br /&gt;
 		clrf	A3			;Register A löschen&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A0&lt;br /&gt;
 		call	CopyDC&lt;br /&gt;
 		call	AddDC			;gemessene Frequenz * 2&lt;br /&gt;
 		call	CopyDC&lt;br /&gt;
 		call	AddDC			;gemessene Frequenz * 4 = tatsächliche Frequenz&lt;br /&gt;
 		call	DispFrq                 ;eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	TMR0			;Timer0 löschen&lt;br /&gt;
 		movlw	0x34			;Timer1&lt;br /&gt;
 		movwf	T1CON			;konfigurieren&lt;br /&gt;
 		movlw	0x1F			;Timer1 laden (für 0,25 s)&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		clrf	TMR1L&lt;br /&gt;
 		bsf	STATUS,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	STATUS,RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		retfie				;erlaube interrupts und springe zurück zu Main&lt;br /&gt;
 CopyDC  	movf	D0,0&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movf	D1,0&lt;br /&gt;
 		movwf	C1&lt;br /&gt;
 		movf	D2,0&lt;br /&gt;
 		movwf	C2&lt;br /&gt;
 		movf	D3,0&lt;br /&gt;
 		movwf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Ports löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
                 clrf    PORTC&lt;br /&gt;
 		movlw	0x20			;RAM (20-7Fh) löschen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		btfss	FSR,7&lt;br /&gt;
 		goto	$-3     &lt;br /&gt;
 		clrf	ADCON0			;schalte ADC off&lt;br /&gt;
 		movlw	7			;sperre ADC&lt;br /&gt;
 		movwf	ADCON1			;und definiere RA0-7 als digitale I/Os&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		bsf	STATUS,RP0		;bank 1&lt;br /&gt;
 		clrf	TRISA			;alle PORTA,&lt;br /&gt;
 		clrf	TRISB			;alle PORTB,&lt;br /&gt;
                 clrf    TRISC                   ;und alle PORTC Pins als Ausgänge&lt;br /&gt;
 		movlw	0xE7			;Takt für Timer0 vom T0CKI Pin&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	STATUS,RP0		;Bank 0&lt;br /&gt;
 		clrf	TMR0			;Timer0 löschen&lt;br /&gt;
 		movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;(prescaler 8)&lt;br /&gt;
 		movlw	0x1F			;Timer1 laden (für 0,25 s)&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		clrf	TMR1L&lt;br /&gt;
 		bsf	STATUS,RP0              ;start Timer0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Eingang&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad aus und setzt, je nach Drehrichtug 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&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 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. Die Warteschleife &amp;quot;Delay&amp;quot; soll ca. 10ms sein.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTB eigelesen, die alle Bits ausser 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, b.z.w. 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 b.z.w. 02, 10 b.z.w. 13, 20 b.z.w. 23 oder 31 b.z.w. 32) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; b.z.w. &amp;quot;_Fdec&amp;quot; gesetzt. Anschliessend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detailierter 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;
=== Handy Display ===&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und Testprogram für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
&lt;br /&gt;
Hier werden einige Programme presentiert, die das ASM Programmieren erleichtern.&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;
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 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;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>Andy</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=11693</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=11693"/>
				<updated>2007-04-25T20:52:41Z</updated>
		
		<summary type="html">&lt;p&gt;Andy: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einladung zur Diskussion... =&lt;br /&gt;
&lt;br /&gt;
Es wird hier versucht die ASM Programmierung von PIC Mikrocontrollern zu beschreiben.&lt;br /&gt;
&lt;br /&gt;
Damit der enstehende Artikel wirklich nützlich  wird, ist Ihre Mitwirkung nötig. Bitte schreiben Sie uns Ihre Meinung, was eventuell noch geändert (z.B. ergänzt) werden soll in diesem Thread:&lt;br /&gt;
&lt;br /&gt;
http://www.roboternetz.de/phpBB2/viewtopic.php?p=271211#271211&lt;br /&gt;
&lt;br /&gt;
Die Autoren bedanken sich im voraus für jeden Beitrag mit Vorschlägen !&lt;br /&gt;
&lt;br /&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 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 enhä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 Bit mehr als 10 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 = 8d     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, u.s.w. So wie im Dezimalsystem werden führende Nullen nicht geschrieben, aber in einem PIC Register existieren immer 8 Bits also auch führende Nullen. Zum Beispiel die hex Zahl 3h sieht im Register so aus: 00000011b. Bei einer Wandlung bin-&amp;gt;hex fängt man immer von der rechten Seite der bin Zahl an, da die Anzahl führenden Nullen unbekannt ist.&lt;br /&gt;
&lt;br /&gt;
== Speicher und Register ==&lt;br /&gt;
&lt;br /&gt;
Als Speicher bezeichnet man den Teil der Hardware, in den 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 Dataspeicher (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 Mid-Range hat 14-bitige Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bitige 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.&lt;br /&gt;
&lt;br /&gt;
Um ein Databyte 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 absoluter 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 und der Wert aus &amp;quot;Temp&amp;quot; sich im &amp;quot;INDF&amp;quot; Register befindet. 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;, der sich jetzt&lt;br /&gt;
                         ;im &amp;quot;INDF&amp;quot; befindet, wird ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 14-bittigen 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 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. Siehe: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von Mid-Range PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 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 Mid-Range Serie von Microchip sind alle in der &amp;quot;Harvard&amp;quot;-Architektur gefertigt. Das bedeutet, dass Datenspeicher und Programmspeicher einen eigenen Bus zur CPU 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 (beim PIC 14 bit) 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 (fatch)        &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;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen Mid-Range 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 200 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 eigebundenen 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.&lt;br /&gt;
&lt;br /&gt;
Dank der integrierten oder an Portpins angeschlosenen Hardware und dem entsprechenden Program 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;
[[Bild:PAD_beispiel.png|thumb|80px|Beispiel für ein PAD]]&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 die wichtigsten 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 .asm (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 Texdatei mit Erweiterung .hex 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) intalliert werden. Für MPASM benutzer werden auch folgende .pdf 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 Eischalten 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, u.s.w.). Bei diesen reicht es bereits Spannung anzulegen und sie laufen bereits.&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, u.s.w.) 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 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 MCLR Pin angeschlossene Hardware während der Programmierung zu schützen. &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 Versorgungspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF möglichts 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 vermeinden, 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 Program 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;
 	LIST      P=16F84&lt;br /&gt;
 	include &amp;quot;P16F84.inc&amp;quot;           ; 4.000 MHz&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;
== 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össe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Grösse des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, u.s.w.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, u.s.w.).&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ägiges 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. PIC Trainer) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bischen 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 Program 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. Hautprogram (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 Programs 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, u.s.w. 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: [[#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 eledigt 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 prozessorspezifischen UPs erstellt. Um ein lauffähiges Programm zu erstellen, braucht man nur benötigte UPs ins Programm kopieren und ein geeignetes HP, das sie aufruft, schreiben.&lt;br /&gt;
&lt;br /&gt;
Ein ASM Programm (Quellcode) muss in einer Texdatei mit der Endung .asm 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 Assemblerprogram zum Übersetzen. Alles was der Assembler nicht versteht oder nicht richtig ist, erscheint als Fehlermeldungen, die der Programmierer kennen muss um die Fehler korrigieren zu können. Eine .hex Datei wird erst dannn 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;
== Programmdurchlaufdiagramm ==&lt;br /&gt;
&lt;br /&gt;
Der Programdurchlaufdiagram (kurz: PAD) ist eine vorläufige und laufend änderbare Stufe zwischen einer Idee und ihrer Verwirklichung. Er wird erst dann fertig, wenn nach ihm erstelltes ASM Program auf einem µC so wie gewünscht funktioniert. Jedes sein Symbol (ausser &amp;quot;Start/Stop&amp;quot;) muss später als Befehlsreihenfolge für den bestimmten CPU in den Quellcode übertragen werden. 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;
Der PAD ist sehr eifach 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;
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; (Sleep) agewendet 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, endweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung. &lt;br /&gt;
&lt;br /&gt;
Als allgemeinnutziges 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 Hauptprogram 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 gesammten 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; gekenzeichnet 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 Richtungspfeile 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. Ausserdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, u.s.w.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, u.s.w.) 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 Quelcode 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;
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 Hauptprogram 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 fogender 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 der CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (ausser Batteriewechsel) ununterbrochen mit Spannung versorgt.&lt;br /&gt;
&lt;br /&gt;
Für komplizierte Programme ist es 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;
Wenn ein ASM Programm nicht wie geplannt funktioniert, wird zuerst ein Fehler im PAD gesucht. Und erst wenn er i.O. ist, im als fehlerhaft festgestellten Codefragment.&lt;br /&gt;
&lt;br /&gt;
== Hauptprogramm ==&lt;br /&gt;
&lt;br /&gt;
Wie sein Namen schon vermuten lässt, ist das Hauptprogram 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.&lt;br /&gt;
&lt;br /&gt;
Typischer PDA 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 eigeschrieben:&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 UP im HP befinden und die folgenden kommen nach dessen Erstellung und Prüfen 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) aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&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;
                         zurück zum Aufrufer &amp;lt;----------return &lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Program 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 PDA:&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;
                                            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 asführen kann, muss er vollständig und richtig 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 meistens 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 eingeschrieben 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ötigtenen Variablen die gewünschte 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                b.z.w.           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 alle Ports nacheinander gelöscht und 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   PORTA &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anchliessend werden für jeden Port die Werte in TRIS Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRIS 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 TRIS Register sich in der Bank1 befinden, muss im STATUS-Register auf Bank1 und danach zurück auf Bank 0 umgeschaltet werden:&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 TRIS Register nacheinander beschrieben werden.&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) b.z.w. nur als Eingang benutzt werden können. Bei Plannung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich ein bestimmter Pin für die geplannte 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, u.s.w.), 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 Herstellern 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;
                               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;
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;
                                        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;
=== Ausgeben ===&lt;br /&gt;
&lt;br /&gt;
Um ein Bit an einem Portpin auszugeben wird ein bestimmtes 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.&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 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 in 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.&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;
=== 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 dennen ist, dass die Sprungtabellen steuern den Programlauf 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 veschiedenen 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üch zum Aufrufer der Tabelle.&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, 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      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	dt      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	dt      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	dt      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	dt      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	dt      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   u.s.w.&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 0x00 enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator fur Grafikdisplay).&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; dient, genannt. Das ASM Programm,  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;
         u.s.w.&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;
         u.s.w&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;
         u.s.w. &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;
         u.s.w&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;
                 .............&lt;br /&gt;
                 Eigener Code&lt;br /&gt;
                 .............&lt;br /&gt;
                 retfie                  ; hier endet die ISR&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 detailiert das ganze Prozess der Erstellung eines ASM Programms 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;
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: [[#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;
 	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                    ; 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                    ; 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                    ; 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&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 &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 in &amp;quot;Erstes.asm&amp;quot; umbenannt. Diese .asm 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 das 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 in Datenblatt nachschauen. Die Meldungen kommen immer für alle SFRs (Special Function Register) die sich in der Bank 1 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&lt;br /&gt;
 Program Memory Words Free:   972&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;
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 PIC2, auf dem das vorhande ASM Programm für PIC1 laufen soll, zumindest für das ASM Program 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 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;             ; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&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 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;
  	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                    ; 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                    ; 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                    ; 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 &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 afgerufen wurdest &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&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 die Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; ein Codefragment als UP zu definieren erst wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck geeignet nur, wenn der Prozessor zum letzten Aufrufer 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 Parameter vor dem Aufruf des UPs in benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Zahlen von den Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Register durchzuführen (z.B. löschen) geeignet ist Anwendung von Schleifen 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;
 btfss 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 abefragt. 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;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;
Fast alle im ASM Programm ungebrauchten 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, u.s.w.), 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;
= Mid-Range =&lt;br /&gt;
&lt;br /&gt;
Zu Mid-Range gehören alle PICs mit 14-bit langen Befehlen aus den Familien 12FXXX und 16FXXX. &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;
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. &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; oder &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 W and literal - Addiere W und Zahl (k)&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;
&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 ANDLW. Dieser Befehl wird oft benutzt zum Löschen bestimmten Bits im Register ohne restlichen Bits zu beeinflüssen.&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 dem &amp;lt;tt&amp;gt;RETURN&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  Unterprogramm1  ;es wird das Unterprogramm &amp;quot;Unterprogramm1&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;
 Unterprogramm1            ;zählt 10 zum W-Register&lt;br /&gt;
     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 (&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;) wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
:Der Befehl bewirkt das gleiche wie MOVLW 0 und darf im Programmen, die fur zukünftige Anwendung bei den PICs der serie 18F vorgesehen sind, nicht benutzt werden, da sie ihn nicht kennen.&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 0 - 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;
&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 0 - 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;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;
&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;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 IORLW. Dieser Befehl wird oft benutzt zum Setzen bestimmten Bits im Register ohne restlichen Bits zu beeinflüssen.&lt;br /&gt;
&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 kopiert.&lt;br /&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;Temp&amp;quot; wurde mit &amp;quot;Temp   equ   0x20&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   Temp        ;ins W-Register wird die absolute Adresse 0x20 vom &amp;quot;Temp&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 - Kehre zurück aus der Unterbrechung&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. Dieser Befehl wird 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&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 höheren 4 bit (bit7-bit4) mit den niedrigeren 4 bit (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;
&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;
: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;
&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 wird zum Vergleichen zwei Register benutzt.&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;Borrowbit&amp;quot; (to borrow = etwas borgen) dient zum erkennen, wenn ein Übertrag einer Rechenoperation exisitiert. 250+10 ergibt zum Beispiel 4, und setzt dabei das Borrowbit auf 1. Damit kann das Programm erkennen, wenn wieder einmal ein Ergebnis größer als 255 herauskam.&lt;br /&gt;
Bei Subtraktionen (SUBLW und SUBWF) verhält sich das Carry Bit umgekehrt als bei Additionen (ADDWF und ADDLW)!! Zum Beispiel 55-6=49 setzt Carry auf 1 aber 10-25=241 löscht das Carry-Flag.&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;
=== 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;
&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 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;
==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) oder 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;
=== 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 der mit call Hex_Dec 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 absolute 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 Hifsregister. 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; entschprechend 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 zum C addiert (&amp;quot;AddCB&amp;quot;) wird. Diese dec Zahl wird zum D Register addiert nur wenn entsprechender Bit der hex Zahl gleich 1 ist. Weil im UP &amp;quot;Hex_Dec&amp;quot; immer das bit A0 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 Register 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.&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;
 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	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	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;
 CClr		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&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;
 		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 DAW)&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 Adressse 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;
                                   u.s.w.&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 fur Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adreesse &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 Programmteil misst eine Frequenz an TOCKI Pin und wurde für PIC16F870 geschrieben. &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;
Es fehlen UPs &amp;quot;Hex_Dec&amp;quot; [[#Hex Dec Wandlung|Hex Dec Wandlung]] und Ausgabe auf ein Display &amp;quot;DispFrq&amp;quot;. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts ausser warten auf ein Interrupt von Timer0 bzw. Timer1. Man kann die Marke &amp;quot;Main&amp;quot; weglassen und das HP als &amp;quot;goto $&amp;quot; formulieren.&lt;br /&gt;
&lt;br /&gt;
Der Zähler der Frequenz wurde um ein Zähler aus zwei zusätzlichen Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TIMER0 ins A1 kopiert. Somit ergibt sich 32-bittiger Ergebniss, 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 biliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Es wird kein zusätzliches Register benötigt, da das &amp;quot;ATmp&amp;quot; und das &amp;quot;RTmp&amp;quot; die gleichen wie im UP &amp;quot;Hex_Dec&amp;quot; sind. Die Quarzfrequenz wurde gewählt, weil sie am nächsten der Temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist. Der PIC16F870 wurde nur wegen nötigen 19 I/O Pins für 6-stelligen 7-segment LCD Display LPH2673-1[[http://www.roboternetz.de/phpBB2/viewtopic.php?t=26005]] (ohne Kontroller) vom Pollin  angewendet. Mit einem üblichen 1x16 Zeichen LCD Matrixdisplay und anderen PICs wurde das Programm für Frequenzen bis zum 100 MHz mit einer Genauigkeit&lt;br /&gt;
+/- 4 Hz positiv getestet.&lt;br /&gt;
&lt;br /&gt;
Um die Frequenz mit Genauigkeit +/- 1Hz zu messen, muss die Messzeit 1 s von Timer1 erzeugt werden, das nur für Quarz bis 2,048 MHz möglich ist. 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 entsprechend geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Mit dem Quarz 7,3728 MHz wird hier die Messzeit 0,25 s genutzt und die gemessene Frequenz durch 4 multipliziert (mittels 2 Additionen), was die Auflösung von +/- 4 Hz ergibt.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Init&amp;quot; muss selbstverständlich für ein Matrixdisplay um Initialisierung des Displaykontrollers ergänzt werden.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F870&lt;br /&gt;
 	include &amp;quot;P16F870.inc&amp;quot;&lt;br /&gt;
 	__CONFIG	_CP_OFF &amp;amp; _DEBUG_OFF &amp;amp; _WRT_ENABLE_ON &amp;amp; _CPD_OFF &amp;amp; _LVP_OFF &amp;amp; _BODEN_OFF &amp;amp; &lt;br /&gt;
                         _PWRTE_ON &amp;amp; _WDT_OFF &amp;amp; _HS_OSC&lt;br /&gt;
 		ORG	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		goto	Main&lt;br /&gt;
 		ORG	0x0004			;ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE		;interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 übelaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;Timer0 interrupt flag löschen&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2&lt;br /&gt;
 		btfsc	STATUS,C&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                          ;wenn nicht, springe zurück zu Main  &lt;br /&gt;
 		bsf	STATUS,RP0		;stopp Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&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	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	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec&lt;br /&gt;
 		clrf	A3			;Register A löschen&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A0&lt;br /&gt;
 		call	CopyDC&lt;br /&gt;
 		call	AddDC			;gemessene Frequenz * 2&lt;br /&gt;
 		call	CopyDC&lt;br /&gt;
 		call	AddDC			;gemessene Frequenz * 4 = tatsächliche Frequenz&lt;br /&gt;
 		call	DispFrq                 ;eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	TMR0			;Timer0 löschen&lt;br /&gt;
 		movlw	0x34			;Timer1&lt;br /&gt;
 		movwf	T1CON			;konfigurieren&lt;br /&gt;
 		movlw	0x1F			;Timer1 laden (für 0,25 s)&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		clrf	TMR1L&lt;br /&gt;
 		bsf	STATUS,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	STATUS,RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		retfie				;erlaube interrupts und springe zurück zu Main&lt;br /&gt;
 CopyDC  	movf	D0,0&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movf	D1,0&lt;br /&gt;
 		movwf	C1&lt;br /&gt;
 		movf	D2,0&lt;br /&gt;
 		movwf	C2&lt;br /&gt;
 		movf	D3,0&lt;br /&gt;
 		movwf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Ports löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
                 clrf    PORTC&lt;br /&gt;
 		movlw	0x20			;RAM (20-7Fh) löschen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		btfss	FSR,7&lt;br /&gt;
 		goto	$-3     &lt;br /&gt;
 		clrf	ADCON0			;schalte ADC off&lt;br /&gt;
 		movlw	7			;sperre ADC&lt;br /&gt;
 		movwf	ADCON1			;und definiere RA0-7 als digitale I/Os&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		bsf	STATUS,RP0		;bank 1&lt;br /&gt;
 		movlw	0xEF			;alle PORTA Pins als Eingänge&lt;br /&gt;
 		movwf	TRISA			;nur TOCKI (A4) als Ausgang&lt;br /&gt;
 		clrf	TRISB			;alle PORTB&lt;br /&gt;
                 clrf    TRISC                   ;und PORTC Pins als Ausgänge&lt;br /&gt;
 		movlw	0xE7			;Takt für Timer0 vom T0CKI Pin&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	STATUS,RP0		;Bank 0&lt;br /&gt;
 		clrf	TMR0			;Timer0 löschen&lt;br /&gt;
 		movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;(prescaler 8)&lt;br /&gt;
 		movlw	0x1F			;Timer1 laden (für 0,25 s)&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		clrf	TMR1L&lt;br /&gt;
 		bsf	STATUS,RP0              ;start Timer0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Eingang&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad aus und setzt, je nach Drehrichtug und sein Anschluss an PORT (PORTA,0 und PORTA,1), ein Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot;, das vor der nächsten Abfrage, gelöscht werden muss. Zum Auswerten werden 3 Register &amp;quot;MausA&amp;quot;, &amp;quot;MausB&amp;quot; und &amp;quot;MausC&amp;quot; benötigt. Als &amp;quot;_Z&amp;quot; wurde &amp;quot;STATUS,Z&amp;quot; definiert. Die Warteschleife &amp;quot;Delay&amp;quot; dient der Entprellung der Kontakte und soll ca. 10ms sein.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTA eigelesen, die alle Bits ausser 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, b.z.w. 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; (10 b.z.w. 20, 01 b.z.w. 31, 02 b.z.w. 32 oder 13 b.z.w. 23) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; b.z.w. &amp;quot;_Fdec&amp;quot; gesetzt. Anschliessend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detailierter PAD:&lt;br /&gt;
&lt;br /&gt;
                                       Mouse      V&lt;br /&gt;
                                              PORTA-&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;
                                              PORTA-&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;
                 |                             W-1-&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;
                 |                     |       W-2-&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;
                 |                     |       W-3-&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;
              W-1-&amp;gt;W                   V                    W-1-&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;
              W-2-&amp;gt;W                W-3-&amp;gt;W                  W-2-&amp;gt;W                W-3-&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	PORTA,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	PORTA,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;
=== Handy Display ===&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und Testprogram für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
== Hilfsmittel ==&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 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;
Hardware und Testprogramm: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124559#124559]]    &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>Andy</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=Diskussion:PIC_Assembler&amp;diff=11692</id>
		<title>Diskussion:PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=Diskussion:PIC_Assembler&amp;diff=11692"/>
				<updated>2007-04-25T19:44:00Z</updated>
		
		<summary type="html">&lt;p&gt;Andy: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== vorgeschlagene Gliederung ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;grün = schon fertig&amp;lt;/span&amp;gt;, &amp;lt;span style=&amp;quot;color:orange;&amp;quot;&amp;gt;orange = wird bzw. könnte noch ergänzt werden&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Einladung zur Diskussion...&amp;lt;/span&amp;gt;&lt;br /&gt;
(wird nach Beendigung des Artikels gelöscht)&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Einführung&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Bit, Byte, Nibble, Bin und Hex &amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Speicher und Register &amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Prozessor&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Assembler&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Grundbeschaltung&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Konfiguration&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Wahl des PICs&amp;lt;/span&amp;gt;&lt;br /&gt;
* Programm&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Allgemeines&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Programdurchlaufdiagram&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Hauptprogramm&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Unterprogramm&amp;lt;/span&amp;gt;&lt;br /&gt;
*** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Initialisierung&amp;lt;/span&amp;gt;&lt;br /&gt;
**** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Variablen&amp;lt;/span&amp;gt;&lt;br /&gt;
**** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;I/O Ports&amp;lt;/span&amp;gt;&lt;br /&gt;
**** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Hardware&amp;lt;/span&amp;gt;&lt;br /&gt;
*** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Einlesen&amp;lt;/span&amp;gt;&lt;br /&gt;
*** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Ausgeben&amp;lt;/span&amp;gt;&lt;br /&gt;
*** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Schleifen&amp;lt;/span&amp;gt;&lt;br /&gt;
*** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Pause&amp;lt;/span&amp;gt;&lt;br /&gt;
*** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Tabellen&amp;lt;/span&amp;gt;&lt;br /&gt;
*** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Schnittstellen und Treiber&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Vorlage für MPASM&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Das erste...&amp;lt;/span&amp;gt;&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Für anderen PIC umschreiben&amp;lt;/span&amp;gt;&lt;br /&gt;
* Einbinden&lt;br /&gt;
* Interrupt&lt;br /&gt;
** Prinzip&lt;br /&gt;
** Quellen&lt;br /&gt;
** Interrupt Service Routine&lt;br /&gt;
* &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Optimierung&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Speicherbedarf&amp;lt;/span&amp;gt;&lt;br /&gt;
*** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Programmspeicher&amp;lt;/span&amp;gt;&lt;br /&gt;
*** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;RAM&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Ausführungszeit&amp;lt;/span&amp;gt;&lt;br /&gt;
* Fehlersuche&lt;br /&gt;
* Mid-Range (mit 14 bit Befehlslänge)&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Kurzübersicht Prozessorbefehle&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Ausführliche Beschreibung zu den Befehlen&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Besondere, oft gebrauchte  Register&amp;lt;/span&amp;gt;&lt;br /&gt;
*** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt; STATUS &amp;lt;/SPAN&amp;gt;&lt;br /&gt;
*** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt; INTCON &amp;lt;/SPAN&amp;gt;&lt;br /&gt;
*** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt; TRIS &amp;lt;/SPAN&amp;gt;&lt;br /&gt;
*** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt; PORT &amp;lt;/SPAN&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Bänke (sowohl die bei mehr als 2k Befehle als auch die bei den normalen speicher bänken)&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Flagsüberprüfung im STATUS-Register&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:orange;&amp;quot;&amp;gt;Codeschnipsel&amp;lt;/SPAN&amp;gt;&lt;br /&gt;
*** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt; A/D-Wandler &amp;lt;/SPAN&amp;gt;&lt;br /&gt;
*** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Hex Dec Wandlung&amp;lt;/SPAN&amp;gt;&lt;br /&gt;
*** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;EEPROM&amp;lt;/span&amp;gt;&lt;br /&gt;
*** PWM&lt;br /&gt;
*** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Interrupts&amp;lt;/span&amp;gt;&lt;br /&gt;
*** RS232 mit PC&lt;br /&gt;
*** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Mausrad&amp;lt;/span&amp;gt;&lt;br /&gt;
*** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;Handy Display&amp;lt;/span&amp;gt;&lt;br /&gt;
** &amp;lt;span style=&amp;quot;color:orange;&amp;quot;&amp;gt;Hilfsmittel&amp;lt;/span&amp;gt;&lt;br /&gt;
*** &amp;lt;span style=&amp;quot;color:green;&amp;quot;&amp;gt;PIC Miniterminal&amp;lt;/span&amp;gt; (mit Dot-Matrix LCD und drei Tasten, benötigt nur 2 I/O Pins vom PIC) (Hardware)&lt;br /&gt;
*** PIC RAM Monitor (mit eigenem Interrupt, zeigt Registerinhalte sogar wenn das Programm in endloser Schleife läuft, was besonders für Anfänger nutzlich ist, benötigt PIC Miniterminal)&lt;br /&gt;
*** PIC Trainer (Hilfswerkzeug für PIC Versuchsprogramme, benötigt PIC Miniterminal)&lt;br /&gt;
*** PIC Profiler (zum messen von Ausführungszeit zwischen call und return, benötigt Display oder PIC Miniterminal)&lt;br /&gt;
* High-End (mit 16 bit Befehlslänge)--&amp;gt;(?)&lt;br /&gt;
&lt;br /&gt;
== Allgemeines ==&lt;br /&gt;
-------&lt;br /&gt;
... gelöschte Diskussion ...&lt;br /&gt;
----&lt;br /&gt;
joa. passt doch. ich mach dir dann wieder paar bilder. mal schaun ob ich es heute noch schaffe. [[Benutzer:Benedikt.Seidl|Benedikt.Seidl]] 08:52, 1. Apr 2007 (CEST)&lt;br /&gt;
-----&lt;br /&gt;
Vielen Dank im voraus!:) Wenn Du die drei Symbole die im PAD auftreten einzeln kopieren kannst, müsste es ziemlich schnell gehen. Nach der neuer Gliederung müsste ich jetzt über Quellcode schreiben, also schon (aber nur) &amp;quot;call&amp;quot; und &amp;quot;goto&amp;quot; einführen. Sonst werde ich alles im Textform (Kommentar) schreiben. Ich meine, dass es unvermeindbar ist, weil irgendwan es sowieso anfangen wird. Ich habe noch eine Frage an Dich. Würdest Du die MPASM Direktiven erklären, die ich von &amp;quot;deinem&amp;quot; in &amp;quot;mein&amp;quot; Teil verschoben habe?[[Benutzer:PICture|PICture]] 09:33, 1. Apr 2007 (CEST)&lt;br /&gt;
-----&lt;br /&gt;
wie meinst du? ich mache halt noch eine erklärung für alle befehle, brauche nur noch bisschen zeit, werde heute leider nicht dazukommen, da ich unterwegs bin :-/ aber in absehbarer zeit werde ich auch noch die anderen befehle beschreiben, und dann mir ein neues thema suchen ;-) [[Benutzer:Benedikt.Seidl|Benedikt.Seidl]] 18:54, 1. Apr 2007 (CEST)&lt;br /&gt;
------&lt;br /&gt;
Es hat sich schon erledigt. Ich habe es als unnötig gestuft und gelöscht. Ab jetzt wird ganz einfache Darstellung von PADs verwendet und es bleibt nur einer in Grafik zu verwandeln (PAD). Die alle anderen (PAD1, PAD2, PAD3, PAD4, und die noch kommen...) bleiben so, wie sie sind/werden. Und weiter würdest Du (hoffentlich) nichts mehr für mich zu tun haben. :)[[Benutzer:PICture|PICture]] 00:12, 2. Apr 2007 (CEST)&lt;br /&gt;
------&lt;br /&gt;
jetzt wollte ich mir ein neues thema raussuchen, was ich noch schreiben könnte, aber muss irgendwie zugeben, dass ich mit den befehlen schon mit meinem latein am ende bin :-/ also ich könnte schon bisschen was schreiben, aber so richtig sicher bin ich mir dabei dann nicht immer. [[Benutzer:Benedikt.Seidl|Benedikt.Seidl]] 12:25, 5. Apr 2007 (CEST)&lt;br /&gt;
------&lt;br /&gt;
Macht ja nichts. Wir arbeiten an dem Artikel bis zum Ende zusammen. Du hast mir schon viel geholfen, dann helfe ich Dir auch immer wieder. Ich versuche möglichst kurz das wichtigste schreiben, aber weiss ich selber nicht, ob das verständlich ist, da ich das alles sehr gut verstehe :). Was Dir nicht gefällt oder nicht genug verständlich ist kannst Du immer ändern (so wie bei der Grundbeschaltung) oder fragen (so wie mit den Buchstaben &amp;quot;C&amp;quot; und &amp;quot;F&amp;quot;). Wie Du sicher bemerkt hast, habe ich in den Befehlen auch ein bischen geändert. Jemand hat gesagt : &amp;quot;Es gibt keine dumme Fragen, nur dumme Antworten&amp;quot; und das stimmt!. Also keine Angst! :) Es gibt auch PN. Für mich ist Deine Meinung sehr wichtig! Ich denke, dass bis Interrupts sollte es schon für Anfänger ausreichen, bin mich aber auch nicht sicher wo eigentlich Ende vom Anfang ist. :) [[Benutzer:PICture|PICture]] 14:24, 5. Apr 2007 (CEST)&lt;br /&gt;
-----&lt;br /&gt;
wow! respekt! geht ja ganz schön schnell voran. das eine pad bekommst du auf jeden fall noch, brauche leider noch ein paar tage. noch dazu müsste ich langsam wirklich fürs abi lernen, aber solange noch andere dinge gehen, werde ich auch hier noch bisschen was machen ;-) [[Benutzer:Benedikt.Seidl|Benedikt.Seidl]] 12:37, 8. Apr 2007 (CEST)&lt;br /&gt;
-----&lt;br /&gt;
Mach Dir bitte mit dem Artikel keinen Stress, ich versuche bloss die freie Tage sinvoll nutzen.:). Es wird danach langsamer gehen, aber die Zeit ist nicht beschränkt. Sogar für die schon als fertig markierte Sachen schreibe ich immer wieder was dazu, was mir noch einfällt.[[Benutzer:PICture|PICture]] 16:11, 8. Apr 2007 (CEST)&lt;br /&gt;
----&lt;br /&gt;
 Bit, Byte, Nibble, Bin und Hex &lt;br /&gt;
also ich würde schon die nummerierung der bits mit aufnehmen. habe mich lange gefragt, wie das funktioniert, weil man ja normalerweise von links nacht rechts zählt und mit 1 anfängt. [[Benutzer:Benedikt.Seidl|Benedikt.Seidl]] 21:28, 9. Apr 2007 (CEST)&lt;br /&gt;
----&lt;br /&gt;
Natürlich! :) Die Numerierung der Bits ist bei jedem Prozessor gleich und fängt immer von links mit 0 (LSB). Ich habe schon eine Idee für erstes ASM Programm, das wird aber noch ein bischen dauern, weil ich das zuerst selber ausprobieren muss (und will). Aber es ist noch weit zum Ende des Artikels. [[Benutzer:PICture|PICture]] 09:27, 10. Apr 2007 (CEST)&lt;br /&gt;
----&lt;br /&gt;
mein fehler. habe da wohl was verwechselt. sorry. die zahlen sind ja doch noch da :-/ [[Benutzer:Benedikt.Seidl|Benedikt.Seidl]] 12:52, 10. Apr 2007 (CEST)&lt;br /&gt;
----&lt;br /&gt;
@Benedikt.Seidl&lt;br /&gt;
&lt;br /&gt;
Schau, bitte, am Anfang des Artikels habe ich noch was neues eingefügt. Als Folge haben wir noch einen Autor (den Gärtner), der schon wichtige Sachen toll ergänzt hat.&lt;br /&gt;
&lt;br /&gt;
@Gärtner&lt;br /&gt;
&lt;br /&gt;
Wenn Du willst, kannst auch etwas neues, wass noch nicht grün gekenzeichnet ist, anfangen. :)&lt;br /&gt;
[[Benutzer:PICture|PICture]] 13:17, 10. Apr 2007 (CEST)&lt;br /&gt;
----&lt;br /&gt;
wow! glückwunsch! http://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=14953 [[Benutzer:Benedikt.Seidl|Benedikt.Seidl]] 16:13, 10. Apr 2007 (CEST)&lt;br /&gt;
----&lt;br /&gt;
Für Dich das gleiche ! Trotzdem schreibe ich weiter.:)[[Benutzer:PICture|PICture]] 16:59, 10. Apr 2007 (CEST)&lt;br /&gt;
----&lt;br /&gt;
Keine Angst, hab auch neues geschrieben ;) Hat wer eine bessere Idee bezüglich Textformation von SFRs? hab mich mal am Datenblatt bedient. Die Assemblerbefehle hab ich heute schon in einen eigenen Artikel geschrieben. Da fehlen nur noch Codeschnippsel. find das Übersichtlicher und werde die DETAILs zu den befehlen von hier bald RAUSLÖSCHEN. (wenn ich mit dem anderen Artikel fertig bin.) --[[Benutzer:Der Gärtner|Der Gärtner]] 18:06, 10. Apr 2007 (CEST)&lt;br /&gt;
----&lt;br /&gt;
:Die Asführliche Beschreibung zu den Befehlen hat der Benedikt.Seidl geschrieben, aber ich glaube, dass er nichts dagegen hätte. Dann werden die Codeschnipsel auch dorthin verschoben, oder ? Es wäre gut wenn Du das Link zu Deinem Artikel in diesen Artikel einfügst. Ich weiss nicht wo ich später die Hifsmittel (kleine Programmierwerkzeuge) hin schreiben soll.[[Benutzer:PICture|PICture]] 18:33, 10. Apr 2007 (CEST)&lt;br /&gt;
----&lt;br /&gt;
:ich finde es schon sehr schade, weil das schon viel arbeit gemacht hat hier. das tabellenlayout hat auch vor und nachteile. aber ich versteh nicht, warum du nicht auf meine beschreibung und code-schnipsel zurückgreifst, bzw. meine befehlsliste ergänzt hast? deine infos bzw. beschreibungen sind wahrscheinlich schon technischer und auch ok, aber für den normalen benutzer oder einsteiger sehe ich es eher als hindernis, wenn so komplizierte beschreibungen verwendet werden. &lt;br /&gt;
: trotzdem finde ich es schön, dass du mitarbeitest, gärtner ;-) [[Benutzer:Benedikt.Seidl|Benedikt.Seidl]] 19:18, 10. Apr 2007 (CEST)&lt;br /&gt;
----&lt;br /&gt;
@ Gärtner&lt;br /&gt;
&lt;br /&gt;
Ich denke auch, dass Löschen nicht nötig ist und Dein Artikel wunderbar als Nachschlagewerk benutzt werden kann, wenn sein Link in diesem Artikel eingefügt wird.[[Benutzer:PICture|PICture]] 19:31, 10. Apr 2007 (CEST)&lt;br /&gt;
----&lt;br /&gt;
@ Gärtner&lt;br /&gt;
&lt;br /&gt;
Erst heute habe ich Dein Artikel aufmerksam durchgelesen und folgendes nicht gut gefunden:&lt;br /&gt;
&lt;br /&gt;
- die Wörter &amp;quot;verundert&amp;quot;, &amp;quot;verodert&amp;quot; und &amp;quot;inklusiv verodert&amp;quot; sind vielleicht &amp;quot;cool&amp;quot; aber für jemanden die die logische Operationen gar nicht kennt, ganz unverständlich.&lt;br /&gt;
&lt;br /&gt;
- bei &amp;quot;call&amp;quot; und &amp;quot;retlw&amp;quot; ist überhaupt nichts über funktionsweise im ASM Programm geschrieben, nur über Register, was nicht besonders wichtig ist. Bei &amp;quot;retfie&amp;quot; fehlt die wichtige Information, dass ausführen des Befehls das Bit GIE setzt, was die Interrupts wieder erlaubt.&lt;br /&gt;
&lt;br /&gt;
- bei &amp;quot;clrw&amp;quot; ist falsches Register und bei &amp;quot;end&amp;quot; falsche Funktion gennant. Ausserdem, ich kenne Keine Pseudobefehle, sondern Direktiven für Assemblerprogramm.&lt;br /&gt;
&lt;br /&gt;
Ohne Beipielen vom Code finde ich das ganze ungeeignet für Anfänger. Bleiben wir, bitte, in dem Artikel, der vor allem für Anfänger vorgesehen ist, bei der ausführlicher Beschreibung vom Benedikt.Seidl.[[Benutzer:PICture|PICture]] 09:08, 11. Apr 2007 (CEST)&lt;br /&gt;
----&lt;br /&gt;
Code kommt noch, und fehler sind echt vorprogramiert gewesen :)&lt;br /&gt;
Ich hab noch einiges an Dingen vor gehabt, die sowieso hier stehen. Die Begriffe &amp;quot;verundet&amp;quot; und &amp;quot;verodert&amp;quot; sind die einzigen, die ich jemals gehört habe, und JA, ich hab vor beispiele zu Schreiben / vom Seidl zu nehmen. Und wenn ich so scharf aufs Löschen wäre, dann hätt ichs schon gemacht :P&lt;br /&gt;
&lt;br /&gt;
Den Begriff &amp;quot;Pseudobefehle&amp;quot; hab ich vom Sprut, kann ich ruhig ändern.&lt;br /&gt;
&lt;br /&gt;
Werd heute da einiges ergänzen und die Register in diesem Beitrag weiter machen.&lt;br /&gt;
--[[Benutzer:Der Gärtner|Der Gärtner]] 11:09, 11. Apr 2007 (CEST) &lt;br /&gt;
----&lt;br /&gt;
@Gärtner&lt;br /&gt;
&lt;br /&gt;
Das hört sich sehr gut an. Deine Beschreibung von Befehlen ist auch nötig, da kann man sofort die Beschreibung für ein Befehl lesen, das man braucht. Sie hat aber sehr langen Inhaltverzeichnis, länger, als dieser ganzen Artikel. Deswegen finde ich die Idee, das getrennt vom Artikel zu machen sehr gut.:) Übrigens, für mich ist der Sprut kein Experte und ich versuche immer mich an der Dokumentation vom Microchip (z.B. MPASM) zu halten um das ganze einheitlich zu gestalten. Es wäre auch eine Möglichkeit, um unnötige Arbeit zu vermeinden, einfach die ganze Beschreibung vom Seidl in Dein Artikel zu übernehmen (eventuell bischen ergänzen) und danach von unserem Artikel löschen und in dem Menüpunkt &amp;quot;Ausführliche Beschreibung zu den Befehlen&amp;quot; nur den Link zu Deinem Artikel lassen. Das scheint mir sogar optimale Lösung zu sein. Ich habe genauso bei &amp;quot;Interface und Treiber&amp;quot; gemacht. Ich werde erst am Wochenende wieder aktiv.[[Benutzer:PICture|PICture]] 19:02, 11. Apr 2007 (CEST)&lt;br /&gt;
----&lt;br /&gt;
Habe den Register INTCON beschrieben... --[[Benutzer:Der Gärtner|Der Gärtner]] 09:07, 12. Apr 2007 (CEST)&lt;br /&gt;
----&lt;br /&gt;
Habe schon dort bischen geändert... Hoffentlich gefällt Dir. :)[[Benutzer:PICture|PICture]] 09:56, 12. Apr 2007 (CEST)&lt;br /&gt;
----&lt;br /&gt;
Ich würde die Register ANSEL und TIMER nicht speziell und so alleine beschreiben. Die gehören entweder zu den ADCs oder zu den einzelnen Timern. &amp;quot;ANSEL&amp;quot; ist z.b. einer von mind. 4 Registern, die von den ADCs benutzt werden. das Selbe gilt für Timer (stichwort TMR0-2 unterschiedliche Architektur/CCPM/PWM...)&lt;br /&gt;
&lt;br /&gt;
@PICture: passt sehr gut, man sieht ich hab die Matura, aber auch, dass ich NICHT in Deutsch maturiert habe - da fehlts an Retorik, Grammatik und Einfühlungsvermögen für nichteingeweihte beim schreiben ;)&lt;br /&gt;
--[[Benutzer:Der Gärtner|Der Gärtner]] 22:48, 12. Apr 2007 (CEST)&lt;br /&gt;
----&lt;br /&gt;
Kleine Frage am Rande, alle Pins an allen Ports der Midrangeserie sind BIDIREKTIONAL - oder...? Ich bin über einen 18F gestolpert, der da aus der Reihe tanzt. (4550er, die USB-Pins...)--[[Benutzer:Der Gärtner|Der Gärtner]] 22:53, 12. Apr 2007 (CEST)&lt;br /&gt;
-----&lt;br /&gt;
@Gärtner&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Nobody is perfect&amp;quot;. Beim jedem Lesen des Artikels finde ich Fehler die ich bisher übersehen habe. Überprüfe noch Deine Logiktabelle für XOR. So wie ich weiss, 1,1-&amp;gt;0. XAND kenne ich nicht.&lt;br /&gt;
&lt;br /&gt;
Wenn es um Mid-Range PICs geht, da sind alle Pins an allen Ports bidirektional. Aber bei fast allen diesen PICs gibt es einen Portpin, der nur open drain ist (z.B. beim 12F629 GPIO,3) und ohne pull-up keine 1 ausgeben kann. Übrigens, was sind &amp;quot;Fusebits&amp;quot; ? Ich (und wahrscheinlich jeder Anfänger auch) habe noch nicht gehört. Ich vermute, dass sich hier um &amp;quot;configuration bits&amp;quot; handelt, es müsste aber irgendwo in unserem Artikel definiert werden. Vielleicht am Ende des Artikels machen wir noch ein &amp;quot;Wörterbuch&amp;quot; für Anfänger ? &lt;br /&gt;
&lt;br /&gt;
Ich freue mich sehr, dass immer mehr Autoren des Artikels gibt. Der nächste, aber fast sicher nicht der letzte, ist der BMS, der gerade ein Codeschnipsel für ADC geschrieben hat. Je mehr Autoren um so besser. Die vorgeschlagene Gliederung ist noch offen und kann jederzeit von jedem geändert werden (z.B. bei der Registerbeschreibung)&lt;br /&gt;
&lt;br /&gt;
@BMS&lt;br /&gt;
&lt;br /&gt;
Dein Codeschnipsel finde ich sehr gut, nur Kleinigkeit gefällt mir nicht: die Kommentare zu den Befehlen befinden sich dazwischen und nicht wie üblich rechts, was den Codefragment schwer durchschaubar macht. [[Benutzer:PICture|PICture]] 07:50, 13. Apr 2007 (CEST)&lt;br /&gt;
----&lt;br /&gt;
@Gärtner&lt;br /&gt;
&lt;br /&gt;
Heute früh habe ich Deinen Artikel durchgelesen und mehrere Fehler gefunden. [[Benutzer:PICture|PICture]] 07:20, 14. Apr 2007 (CEST)&lt;br /&gt;
----&lt;br /&gt;
codeschnipsel werd ich gleich ändern (kommentare)&lt;br /&gt;
bin erst wieder am montag da&lt;br /&gt;
[[Benutzer:BMS|BMS]] 13:35, 17. Apr 2007 (CEST)&lt;br /&gt;
----&lt;br /&gt;
@BMS&lt;br /&gt;
&lt;br /&gt;
Ich habe wieder &amp;quot;ein bischen&amp;quot; geschrieben. Wenn Du Zeit hättest, lese es, bitte, durch und eventuell verbessere oder lösche was Du nicht gut findest. Vielen Dank im voraus.:)[[Benutzer:PICture|PICture]] 10:21, 23. Apr 2007 (CEST)&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
zu: Erklärungen in diesem Artikel.&amp;lt;br&amp;gt;&lt;br /&gt;
Begriffe wie Bit sind schon umfangreich an anderer Stelle erklört, daher wäre es evtl. sinnvoller, lediglich einen Verweis dorthin vorzusehen, statt einer eigenen Erklärung.&amp;lt;br&amp;gt;&lt;br /&gt;
z.B. BIT: http://de.wikipedia.org/wiki/Bit&amp;lt;br&amp;gt;&lt;br /&gt;
Gruß Andreas&lt;/div&gt;</summary>
		<author><name>Andy</name></author>	</entry>

	<entry>
		<id>https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=11691</id>
		<title>PIC Assembler</title>
		<link rel="alternate" type="text/html" href="https://rn-wissen.de/wiki/index.php?title=PIC_Assembler&amp;diff=11691"/>
				<updated>2007-04-25T19:35:14Z</updated>
		
		<summary type="html">&lt;p&gt;Andy: /* Einladung zur Diskussion... */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Einladung zur Diskussion... =&lt;br /&gt;
&lt;br /&gt;
Es wird hier versucht die ASM Programmierung von PIC Mikrocontrollern zu beschreiben.&lt;br /&gt;
&lt;br /&gt;
Damit der enstehende Artikel wirklich nützlich  wird, ist Ihre Mitwirkung nötig. Bitte schreiben Sie uns Ihre Meinung, was eventuell noch geändert (z.B. ergänzt) werden soll in diesem Thread:&lt;br /&gt;
&lt;br /&gt;
http://www.roboternetz.de/phpBB2/viewtopic.php?p=271211#271211&lt;br /&gt;
&lt;br /&gt;
Die Autoren bedanken sich im voraus für jeden Beitrag mit Vorschlägen !&lt;br /&gt;
&lt;br /&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. Der Bit ist binär, weil er nur zwei unterschiedliche Werte 0 bzw. 1 haben kann.&lt;br /&gt;
&lt;br /&gt;
Wenn wir gleichzeitig (paralell) 8 Bits haben, dann ist es ein Byte, der 256 Bitkombinationen von 00000000b bis 11111111b enhä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, das es sich um binäre (kurz: bin) Darstellung (auch Zahl genannt) handelt. Binäre Zahlen sind aber lang, weil jeder 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 Bit mehr als 10 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 = 8d     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, u.s.w. So wie im Dezimalsystem werden führende Nullen nicht geschrieben, aber in einem PIC Register existieren immer 8 Bits also auch führende Nullen. Zum Beispiel die hex Zahl 3h sieht im Register so aus: 00000011b. Bei einer Wandlung bin-&amp;gt;hex fängt man immer von der rechten Seite der bin Zahl an, da die Anzahl führenden Nullen unbekannt ist.&lt;br /&gt;
&lt;br /&gt;
== Speicher und Register ==&lt;br /&gt;
&lt;br /&gt;
Als Speicher bezeichnet man ein Teil der Hardware, in die eine Information eingeschrieben, in der gespeichert und aus der wieder ausgelesen werden kann.&lt;br /&gt;
&lt;br /&gt;
Es gibt eigentlich nur zwei Arten von elektronischen Speicher: 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 Dataspeicher (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, das die flüchtigen direkt (sehr schnell) beschreibbar sind und das Beschreiben den nichtflüchtigen benötigt spezielle Algorithmen, die leider im Vergleich zu direkten Zugriffen langsamer sind. Beim Auslesen gibt es praktisch keinen Unterschied.&lt;br /&gt;
&lt;br /&gt;
Ein Speicher besitzt bestimmte Menge von s.g. Speicherstellen. Jede Speicherstelle hat seine individuelle Adresse und kann eine binäre Information mit bestimmter Anzahl von Bits abspeichern. &lt;br /&gt;
&lt;br /&gt;
Bei PIC haben die drei Arten von Speicher, wegen verschiedener Anwendung, auch unterschiedliche Struktur. Die beiden Speicher für Daten (RAM und EEPROM) haben jeweils 8-bitigen und Programmspeicher (Flasch) bei Mid-Range hat 14-bitigen Speicherstellen. Die Anzahl den Speicherstellen im bestimmten Speicher ist vom PIC-Typ abhängig.&lt;br /&gt;
&lt;br /&gt;
Eine 8-bitige Speicherstelle im RAM wird bei PICs Register genannt und kann so skiziert 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;
Der bit 7 wird als hochwertigste (MSB = Most Significant Bit) und bit0 als niederwertigste (LSB = Least Significant Bit) bezeichnet. Jeder Bit im Register (X) kann gleich 0 bzw. 1 sein.&lt;br /&gt;
&lt;br /&gt;
Um ein Databyte in ein Register schreiben oder aus einem Register 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 definierten 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 den die absolute Adresse des Registers &amp;quot;Temp&amp;quot; eingeschrieben wird und der Wert aus dem &amp;quot;Temp&amp;quot; sich im &amp;quot;INDF&amp;quot; Register befindet. 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;, der sich jetzt&lt;br /&gt;
                         ;im &amp;quot;INDF&amp;quot; befindet, wird ins W-Register geladen.&lt;br /&gt;
&lt;br /&gt;
Weil in jedem 14-bittigem Befehl, der mit Datenspeicher verbunden ist, fur Adresse des ansprechenden Registers nur 7 Bits existieren, die bis zum 7Fh (128d) Register direkt ansprechen können, ist bei PICs der Datenspeicher (RAM) in s.g. Bänke verteilt.&lt;br /&gt;
&lt;br /&gt;
Für Aswahl 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 von Bänke und ihre Verwendung ist von gesamter Grösse des RAMs abhängig und kann dem Datenblatt des PICs entnommen werden. Siehe: [[#Speicherbankorganisation|Speicherbankorganisation]]&lt;br /&gt;
&lt;br /&gt;
== Prozessor ==&lt;br /&gt;
&lt;br /&gt;
Der Prozessor von Mid-Range PICs gehört zu den RISC (Reduced Instruction Set Computer) Prozessoren und man hat nur 35 Befehle zu Erlernen, was seine Programmierung im Vergleich zu anderen µC 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 zwischen 1-2 Prozessortakten.&lt;br /&gt;
&lt;br /&gt;
Die Prozessoren der Mid-Range Serie von Microchip sind alle in der &amp;quot;Harvard&amp;quot;-Architektur gefertigt. Das Bedeuted, dass der Datenspeicher und Programmspeicher einen eigenen Bus zur CPU 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 (beim PIC 14 bit) kann in nur einem Takt verarbeitet werden. Daher kommt auch das Aufteilen der Ausführung des Befehls in die 4 verschiedenen Vörgänge. Wärend der neue Befehl eingelesen (&amp;quot;gefatched&amp;quot;) wird, wird der Vorige gerade gelesen (&amp;quot;read&amp;quot;) und der Vorvorige verarbeited (&amp;quot;executed&amp;quot;) und der Vorvorvorige schreibt gerade in den Datenspeicher (&amp;quot;write&amp;quot;). Das heist 4 Befehle werden jeweils um einen Oszillatortaktzyklus verschoben gleichzeitig verarbeitet.&lt;br /&gt;
&lt;br /&gt;
Das  geschieht in vier Perioden des Oszillators. Deswegen die Taktfrequenz des CPUs entspricht durch 4 geteilter Frequenz des Oszillators.&lt;br /&gt;
                 &lt;br /&gt;
                 CPU Vorgang                   Richtung   Speicher&lt;br /&gt;
                 -------------------------------------------------   -&lt;br /&gt;
                 1.Befehl lesen (fatch)        &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;
Das Lesen/Schreiben aus/in den EEPROM Speicher ist mit Hilfe speziellen Register und Unterprogrammen bei allen Mid-Range 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 genützt 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 bestimmter 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 englischer Sprache stammt. Siehe: [[#Kurzübersicht Assembler Befehle|Kurzübersicht Assembler Befehle]]&lt;br /&gt;
 &lt;br /&gt;
Obwohl sie 200 bis 1000 mal schneller als die meisten Hochsprachen ist, wird sie wegen dem grossen Aufwand bei Erstellung umfangreichen Programmen, selten benutzt. Man findet sie aber oft in fast allen Hochsprachen, in eigebundenen Funktionen, überall dort wo die Hochsprachen zu langsam sind oder nötigen Aufgaben nicht unterstützen (z.B. Maus in Q-Basic).&lt;br /&gt;
&lt;br /&gt;
ASM eignet sich aber 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.&lt;br /&gt;
&lt;br /&gt;
Dank der integrierten oder an Portpins angeschlosenen Hardware und dem entsprechenden Program 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;) und der bestimmte CPU &amp;quot;versteht&amp;quot;. Sie endet eigentlich erst dann, wenn das geschriebene Programm so wie geplannt funktioniert.&lt;br /&gt;
&lt;br /&gt;
[[Bild:PAD_beispiel.png|thumb|80px|Beispiel für ein PAD]]&lt;br /&gt;
&lt;br /&gt;
Weil ASM Programme nicht besonders durchschaubar sind, wurde als Hilfsmittel ein Programmablaufdiagramm (kurz: PAD) erfunden. Beim Programmerstellung fängt man damit an ein PAD zu erstellen, das die wichtigsten 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 .asm (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 Texdatei mit Erweiterung .hex 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) intalliert werden. Für MPASM benutzer werden auch folgende .pdf 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 Eischalten 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 auf zufälliger Stelle zu unterbrechen,&lt;br /&gt;
aber keine um ihn auf 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 der CPU eine Meldung ausgibt, dass er sich schon auf der &amp;quot;STOP&amp;quot; Stelle des Programms befinet. Es muss auch&lt;br /&gt;
definiert werden (z.B. durch eine Tastenkombination), wann der 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, u.s.w.). Bei diesen reicht es bereits Spannung anzulegen und sie laufen bereits.&lt;br /&gt;
Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, u.s.w.) 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 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 MCLR Pin angeschlossene Hardware während der Programmierung zu schützen. &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 Versorgungspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF möglichts 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; festprogrammiert. Sie ist eigentlich für fast jeden PIC-Typ anders. Um Probleme zu vermeinden, muss sie für bestimmten PIC aus einer im MPASM Verzeichniss enthaltener 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 Program 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;
 	LIST      P=16F84&lt;br /&gt;
 	include &amp;quot;P16F84.inc&amp;quot;           ; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _XT_OSC&lt;br /&gt;
&lt;br /&gt;
Die alle Optionen müssen gross geschrieben sein, genauso wie in der &amp;quot;*.inc&amp;quot; Datei.&lt;br /&gt;
&lt;br /&gt;
== Wahl des PICs ==&lt;br /&gt;
&lt;br /&gt;
Es gibt PIC µC die im 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össe des Datenspeichers (für Variablen).&lt;br /&gt;
&lt;br /&gt;
- Grösse des Programmspeichers (für Programm).&lt;br /&gt;
&lt;br /&gt;
- Integrierte Hardware (Komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, u.s.w.).&lt;br /&gt;
&lt;br /&gt;
- Freie I/O Pins für externe Hardware (Display, Tasten, u.s.w.).&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ägiges Programms, der tatsächlich nötiger, da seine Parameter am Anfang nur geschätzt werden können. Wenn man viel Programme für verschiedene PICs entwickelt, optimal wäre der grösste PIC16F877 mit 20 MHz max. Taktfrequenz. &lt;br /&gt;
&lt;br /&gt;
Diese Lösung hat auch den Vorteil, dass während der Programmerstellung kurze Hilfsprogramme (z.B. PIC Trainer) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bischen 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 Program kann man auf klenere Fragmente unterteilen, die auf bestimmter Weise miteinander verknüpft sind und gemeinsam die Aufgabe des Programms erfüllen. Das wichtigste Teil eines Programms ist s.g. Hautprogram (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 Programs ist aber komplizierter, da ein UP kann auch ein oder mehrere UPs nacheinander aufrufen. 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, u.s.w. 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. Sishe hierzu: [[#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 eledigt werden muss. Weil das nicht egal ist, welches UP augerufen 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 änlich wie bei Hochsprachen, wenn man sich Bibliotheken mit Prozessorspezifischen UPs erstellt. Um ein lauffähiges Programm zu erstellen, braucht man nur benötigte UPs ins Program kopieren und ein geignetes HP, das sie aufruft, schreiben.&lt;br /&gt;
&lt;br /&gt;
Ein ASM Programm (Quellcode) muss in einer Texdatei .asm in der vom Assemblerprogramm erwarteter Form verfasst werden, um fehlerfreie Konvertierung in die Maschinensprache (Assemblierung) zu gewährleisten. Dieses Prozess verläuft in der Form eines Dialoges.&lt;br /&gt;
&lt;br /&gt;
Der Programmierer schreibt und gibt es dem Assemblerprogram zum Übersetzen. Alles was das Programm nicht versteht oder nicht richtig ist, erscheint als Fehlermeldungen, die der Programmierer kennen muss um die Fehler korrigieren zu können. Eine .hex Datei wird erst dannn erstellt, wenn das Assemblerprogramm keine Fehler mehr im Quellcode findet. Deswegen sehr wichtig ist, sich mit dem Assemblerprogramm vertaut zu machen, um die Dialogzeit zu minimieren.&lt;br /&gt;
&lt;br /&gt;
== Programmdurchlaufdiagramm ==&lt;br /&gt;
&lt;br /&gt;
Der Programdurchlaufdiagram (kurz: PAD) ist eine vorläufige und laufend änderbare Stufe zwischen einer Idee und ihrer Verwirklichung. Er wird erst dann fertig, wenn nach ihm erstelltes ASM Program auf einem µC so wie gewünscht funktioniert. Jedes sein Symbol (ausser &amp;quot;Start/Stop&amp;quot;) muss später als Befehlsreihenfolge für den bestimmten CPU in den Quellcode übertragen werden. 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;
Der PAD ist sehr eifach 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;
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; (Sleep) agewendet 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, endweder in der &amp;quot;ja&amp;quot; (J) oder &amp;quot;nein&amp;quot; (N) Richtung. &lt;br /&gt;
&lt;br /&gt;
Als allgemeinnutziges 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 Hauptprogram 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 in EEPROM speichert.&lt;br /&gt;
&lt;br /&gt;
Es ist nicht nötig immer die Symbole zu zeichnen, man kann sich sie vorstellen und nur den Text schreiben. Die Prüfungen werden mit &amp;quot;?&amp;quot; gekenzeichnet 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 unbedeutende 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, das der Inhalt des A Registers ins W-Register geladen (kopiert) wird. Ausserdem werden Zeichen (&amp;quot;+&amp;quot;, &amp;quot;-&amp;quot;, &amp;quot;*&amp;quot;, &amp;quot;/&amp;quot;, &amp;quot;^&amp;quot;, u.s.w.) für arithmetische und (&amp;quot;&amp;amp;&amp;quot;, &amp;quot;or&amp;quot;, &amp;quot;xor&amp;quot;, u.s.w.) für logische Operationen angewendet. In ein Quellcode werden für diese Zeichen entsprechende Befehle eingeschrieben. 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 Quelcode 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;
Der PAD1 kann aber für Hauptprogramme, die in beliebigem Moment unterbrochen werden dürfen, deutlich vereifacht werden, da die Prüfung &amp;quot;Ende?&amp;quot; ob das Hauptprogram 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 fogender PAD angewendet, weil es ziemlich einfach festzustellen&lt;br /&gt;
ist (z.B. durch Stromverbrauchmessung des µCs), wann sich der 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 der CPU jede Minute vom Timer aufgeweckt wird, um die Zeit zu aktualisieren. Eine Uhr ist immer (ausser Batteriewechsel) ununterbrochen mit Spannung versorgt.&lt;br /&gt;
&lt;br /&gt;
Für komplizierte Programme ist es 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 schaft, 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;
Wenn ein ASM Programm nicht wie geplannt funktioniert, wird zuerst ein Fehler im PAD gesucht. Und erst wenn er i.O. ist, im als fehlerhaft festgestellten Codefragment.&lt;br /&gt;
&lt;br /&gt;
== Hauptprogramm ==&lt;br /&gt;
&lt;br /&gt;
Wie sein Namen schon vermuten lässt, ist das Hauptprogram 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 nachainander 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 die alle, die durch die UPS realisierte Aufgaben quasi gleichzeitig ausgeführt. Wenn es unerwünscht ist, müssen einige UPs als Verzögerungen realisiert werden.&lt;br /&gt;
&lt;br /&gt;
Typischer PDA 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 eigeschrieben:&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 UP im HP befinden und die folgenden kommen nach dessen Erstellung und Prüfen 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) aufgerufen und nach seinem Ausführen, wird zurück zum Aufrufer gesprungen. Der Rückkehr zum Aufrufer wird durch &amp;quot;return&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;
                         zurück zum Aufrufer &amp;lt;----------return &lt;br /&gt;
&lt;br /&gt;
Ein HP von einem ASM Programm kann in anderem, mehr umfangreichem ASM Program 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 PDA:&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;
                                            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 asführen kann, muss er vollständig und richtig 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 nach dem Einschalten der Spannung im RAM sich zufällige Werte befinden, wird meistens als erstes, der benutzte Bereich des RAMs (z.B. 20h bis 7Fh) gelöscht. Es wird einfach und sparsam mit einer Schleife, die indirekte Adressierung verwendet, gemacht:&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 eingeschrieben 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 zur aktueller Adresse -3&lt;br /&gt;
                                             return&lt;br /&gt;
&lt;br /&gt;
Danach können den benötigtenen Variablen die gewünschte Werte angegeben 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 Eischreiben in entsprechenden Register (CMCON bzw. ADCON1) des Wertes 7:&lt;br /&gt;
&lt;br /&gt;
                      movlw   7                b.z.w.           movlw   7             &lt;br /&gt;
                      movwf   CMCON                             movwf   ADCON1&lt;br /&gt;
&lt;br /&gt;
Wenn einige als Analoge Eingänge benutzt werden sollen, mussen die entsprechende Werte dem Datenblatt des jeweiligen PICs entnommen werden. &lt;br /&gt;
&lt;br /&gt;
Danach werden alle Ports nacheinander gelöscht und 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   PORTA &lt;br /&gt;
                                       usw.&lt;br /&gt;
&lt;br /&gt;
Anchliessend werden für jeden Port die Werte in TRIS Register eingeschrieben, wobei ein Bit einem Pin entspricht. Ein Pin wird in TRIS 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 TRIS Register sich in der Bank1 befinden, muss im STATUS-Register auf Bank1 und danach zurück auf Bank 0 umgeschaltet werden:&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 TRIS Register nacheinander beschrieben werden.&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) b.z.w. nur als Eingang benutzt werden können. Bei Plannung der Verwendung von PORTA muss immer im Datenblatt geprüft werden, ob sich bestimmter Pin für geplannte 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, u.s.w.), 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 Herstellern 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;
                               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;
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;
                                        bcf     Tasten,1&lt;br /&gt;
                                        btfsc   PORTA,3&lt;br /&gt;
                                        bsf     Tasten,1&lt;br /&gt;
&lt;br /&gt;
Natürlich wenn ein ganzer Byte vom Port in das W-Register eingelesen wird, kann mann den gleich in das Zielregister schreiben.&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 er einfach zuerst in das W-Register geladen und danach an 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;
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 ein 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.&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 aktueller 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 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 in 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.&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;
=== 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 dennen ist, dass die Sprungtabellen steuern den Programlauf 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 veschiedenen 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üch zum Aufrufer der Tabelle.&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, 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      0x03, 0xE8                         ; 0x00&lt;br /&gt;
 	dt      0x03, 0xE8                         ; 0x02&lt;br /&gt;
 	dt      'M','H','z',0x00                   ; 0x04&lt;br /&gt;
 	dt      ' ',' ','W','A','I','T',0x00       ; 0x08&lt;br /&gt;
 	dt      'C','o','n','s','t',' ','X',0x00   ; 0x0F&lt;br /&gt;
 	dt      'C','=',0x00                       ; 0x17&lt;br /&gt;
 	dt      'L','=',0x00                       ; 0x1A&lt;br /&gt;
 	dt      'F','=',0x00                       ; 0x1D&lt;br /&gt;
 	dt      'O','K',0x00                       ; 0x20&lt;br /&gt;
                                   u.s.w.&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 0x00 enden, der hier als Stringende dient.  Einfacher ist, wenn alle Strings gleich lang sind (wie z.B. in einem Zeichengenerator fur Grafikdisplay).&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; dient, genannt. Das ASM Programm,  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;
         u.s.w.&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;
         u.s.w&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;
         u.s.w. &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;
         u.s.w&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;
                 .............&lt;br /&gt;
                 Eigener Code&lt;br /&gt;
                 .............&lt;br /&gt;
                 retfie                  ; hier endet die ISR&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 detailiert das ganze Prozess der Erstellung eines ASM Programms 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;
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: [[#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;
 	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                    ; 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                    ; 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                    ; 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&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 &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 in &amp;quot;Erstes.asm&amp;quot; umbenannt. Diese .asm 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 das 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 in Datenblatt nachschauen. Die Meldungen kommen immer für alle SFRs (Special Function Register) die sich in der Bank 1 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&lt;br /&gt;
 Program Memory Words Free:   972&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;
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 PIC2, auf dem das vorhande ASM Programm für PIC1 laufen soll, zumindest für das ASM Program 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 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;             ; 4.000 MHz&lt;br /&gt;
 	__config _CP_OFF &amp;amp; _WDT_OFF &amp;amp; _PWRTE_ON &amp;amp; _HS_OSC&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 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;
  	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                    ; 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                    ; 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                    ; 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 &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 afgerufen wurdest &lt;br /&gt;
                                        ; hier endet das gesamte ASM Programm &lt;br /&gt;
          end                           ; MPASM Direktive&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 die Unterprogramme meistens mit dem &amp;quot;call&amp;quot;-Befehl. Es &amp;quot;lohnt sich&amp;quot; ein Codefragment als UP zu definieren erst wenn es min. 2 mal aufgerufen wird. &lt;br /&gt;
&lt;br /&gt;
Ein &amp;quot;goto&amp;quot;-Befehl ist zu diesem Zweck geeignet nur, wenn der Prozessor zum letzten Aufrufer 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 Parameter vor dem Aufruf des UPs in benötigte Anzahl von Register einschreben und dann das Unterprogramm mit &amp;quot;call&amp;quot; aufrufen. Das Unterprogramm verwendet dann die Zahlen von den Register. Siehe: [[#Pause|Pause]]&lt;br /&gt;
&lt;br /&gt;
Um gleiche Vorgänge in mehreren Register durchzuführen (z.B. löschen) geeignet ist Anwendung von Schleifen 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;
 btfss 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 abefragt. 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;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;
Fast alle im ASM Programm ungebrauchten 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, u.s.w.), 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;
= Mid-Range =&lt;br /&gt;
&lt;br /&gt;
Zu Mid-Range gehören alle PICs mit 14-bit langen Befehlen aus den Familien 12FXXX und 16FXXX. &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;
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. &amp;lt;tt&amp;gt;0x20&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;d'42'&amp;lt;/tt&amp;gt; oder &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 W and literal - Addiere W und Zahl (k)&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;
&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 ANDLW. Dieser Befehl wird oft benutzt zum Löschen bestimmten Bits im Register ohne restlichen Bits zu beeinflüssen.&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 dem &amp;lt;tt&amp;gt;RETURN&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  Unterprogramm1  ;es wird das Unterprogramm &amp;quot;Unterprogramm1&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;
 Unterprogramm1            ;zählt 10 zum W-Register&lt;br /&gt;
     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 (&amp;lt;tt&amp;gt;W&amp;lt;/tt&amp;gt;) wird mit Nullen gefüllt (gelöscht).&lt;br /&gt;
:Der Befehl bewirkt das gleiche wie MOVLW 0 und darf im Programmen, die fur zukünftige Anwendung bei den PICs der serie 18F vorgesehen sind, nicht benutzt werden, da sie ihn nicht kennen.&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 0 - 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;
&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 0 - 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;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;
&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;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 IORLW. Dieser Befehl wird oft benutzt zum Setzen bestimmten Bits im Register ohne restlichen Bits zu beeinflüssen.&lt;br /&gt;
&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 kopiert.&lt;br /&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;Temp&amp;quot; wurde mit &amp;quot;Temp   equ   0x20&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   Temp        ;ins W-Register wird die absolute Adresse 0x20 vom &amp;quot;Temp&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 - Kehre zurück aus der Unterbrechung&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. Dieser Befehl wird 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&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 höheren 4 bit (bit7-bit4) mit den niedrigeren 4 bit (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;
&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;
: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;
&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 wird zum Vergleichen zwei Register benutzt.&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;Borrowbit&amp;quot; (to borrow = etwas borgen) dient zum erkennen, wenn ein Übertrag einer Rechenoperation exisitiert. 250+10 ergibt zum Beispiel 4, und setzt dabei das Borrowbit auf 1. Damit kann das Programm erkennen, wenn wieder einmal ein Ergebnis größer als 255 herauskam.&lt;br /&gt;
Bei Subtraktionen (SUBLW und SUBWF) verhält sich das Carry Bit umgekehrt als bei Additionen (ADDWF und ADDLW)!! Zum Beispiel 55-6=49 setzt Carry auf 1 aber 10-25=241 löscht das Carry-Flag.&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;
=== 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;
&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 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;
==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) oder 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;
=== 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 der mit call Hex_Dec 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 absolute 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 Hifsregister. 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; entschprechend 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 zum C addiert (&amp;quot;AddCB&amp;quot;) wird. Diese dec Zahl wird zum D Register addiert nur wenn entsprechender Bit der hex Zahl gleich 1 ist. Weil im UP &amp;quot;Hex_Dec&amp;quot; immer das bit A0 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 Register 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.&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;
 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	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	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;
 CClr		clrf	C0&lt;br /&gt;
 		clrf	C1&lt;br /&gt;
 		clrf	C2&lt;br /&gt;
 		clrf	C3&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;
 		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 DAW)&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 Adressse 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;
                                   u.s.w.&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 fur Grafikdisplay).&lt;br /&gt;
&lt;br /&gt;
Die Adreesse &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 Programmteil misst eine Frequenz an TOCKI Pin und wurde für PIC16F870 geschrieben. &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;
Es fehlen UPs &amp;quot;Hex_Dec&amp;quot; [[#Hex Dec Wandlung|Hex Dec Wandlung]] und Ausgabe auf ein Display &amp;quot;DispFrq&amp;quot;. Das HP (&amp;quot;Main&amp;quot;) als leere endlose Schleife macht nichts ausser warten auf ein Interrupt von Timer0 bzw. Timer1. Man kann die Marke &amp;quot;Main&amp;quot; weglassen und das HP als &amp;quot;goto $&amp;quot; formulieren.&lt;br /&gt;
&lt;br /&gt;
Der Zähler der Frequenz wurde um ein Zähler aus zwei zusätzlichen Register A2 und A3 erweitert und bei jedem Timer0 Überlauf erhöht. Der Prescaler wird ins Register A0 und der TIMER0 ins A1 kopiert. Somit ergibt sich 32-bittiger Ergebniss, 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 biliebigen Display angezeigt werden.&lt;br /&gt;
&lt;br /&gt;
Es wird kein zusätzliches Register benötigt, da das &amp;quot;ATmp&amp;quot; und das &amp;quot;RTmp&amp;quot; die gleichen wie im UP &amp;quot;Hex_Dec&amp;quot; sind. Die Quarzfrequenz wurde gewählt, weil sie am nächsten der Temperaturstabiltesten Frequenz für AT Quarzen 7,2 MHz ist. Der PIC16F870 wurde nur wegen nötigen 19 I/O Pins für 6-stelligen 7-segment LCD Display LPH2673-1[[http://www.roboternetz.de/phpBB2/viewtopic.php?t=26005]] (ohne Kontroller) vom Pollin  angewendet. Mit einem üblichen 1x16 Zeichen LCD Matrixdisplay und anderen PICs wurde das Programm für Frequenzen bis zum 100 MHz mit einer Genauigkeit&lt;br /&gt;
+/- 4 Hz positiv getestet.&lt;br /&gt;
&lt;br /&gt;
Um die Frequenz mit Genauigkeit +/- 1Hz zu messen, muss die Messzeit 1 s von Timer1 erzeugt werden, das nur für Quarz bis 2,048 MHz möglich ist. 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 entsprechend geladen werden.  &lt;br /&gt;
&lt;br /&gt;
Mit dem Quarz 7,3728 MHz wird hier die Messzeit 0,25 s genutzt und die gemessene Frequenz durch 4 multipliziert (mittels 2 Additionen), was die Auflösung von +/- 4 Hz ergibt.&lt;br /&gt;
&lt;br /&gt;
Das UP &amp;quot;Init&amp;quot; muss selbstverständlich für ein Matrixdisplay um Initialisierung des Displaykontrollers ergänzt werden.&lt;br /&gt;
&lt;br /&gt;
 ;	Programm zum Messen der Frequenz an T0CKI Pin mit 7,3728 MHz Quarz &lt;br /&gt;
 	LIST      P=16F870&lt;br /&gt;
 	include &amp;quot;P16F870.inc&amp;quot;&lt;br /&gt;
 	__CONFIG	_CP_OFF &amp;amp; _DEBUG_OFF &amp;amp; _WRT_ENABLE_ON &amp;amp; _CPD_OFF &amp;amp; _LVP_OFF &amp;amp; _BODEN_OFF &amp;amp; &lt;br /&gt;
                         _PWRTE_ON &amp;amp; _WDT_OFF &amp;amp; _HS_OSC&lt;br /&gt;
 		ORG	0x0000&lt;br /&gt;
 		call	Init&lt;br /&gt;
 Main		goto	Main&lt;br /&gt;
 		ORG	0x0004			;ISR (interrupt service routine)&lt;br /&gt;
 		bcf	INTCON,GIE		;interrupts sperren&lt;br /&gt;
 		btfss	INTCON,T0IF		;ist Timer0 übelaufen ?&lt;br /&gt;
 		goto	CheckTMR1               ;nein, dann prüfe Timer1&lt;br /&gt;
 		bcf	INTCON,T0IF		;Timer0 interrupt flag löschen&lt;br /&gt;
 		movlw	1&lt;br /&gt;
 		addwf	A2,1			;erhöhe A2&lt;br /&gt;
 		btfsc	STATUS,C&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                          ;wenn nicht, springe zurück zu Main  &lt;br /&gt;
 		bsf	STATUS,RP0		;stopp Timer0&lt;br /&gt;
 		movf	TRISA,0&lt;br /&gt;
 		andlw	0xEF&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Ausgang&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		bcf	T1CON,TMR1ON		;stopp Timer1&lt;br /&gt;
 		bcf	PIR1,TMR1IF		;Timer1 interrupt flag löschen&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	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	FToggle&lt;br /&gt;
 		comf	ATmp,1&lt;br /&gt;
 		incf	ATmp,0&lt;br /&gt;
 		movwf	A0&lt;br /&gt;
 		call	Hex_Dec&lt;br /&gt;
 		clrf	A3			;Register A löschen&lt;br /&gt;
 		clrf	A2&lt;br /&gt;
 		clrf	A1&lt;br /&gt;
 		clrf	A0&lt;br /&gt;
 		call	CopyDC&lt;br /&gt;
 		call	AddDC			;gemessene Frequenz * 2&lt;br /&gt;
 		call	CopyDC&lt;br /&gt;
 		call	AddDC			;gemessene Frequenz * 4 = tatsächliche Frequenz&lt;br /&gt;
 		call	DispFrq                 ;eigenes UP für benutztes Display&lt;br /&gt;
 		clrf	TMR0			;Timer0 löschen&lt;br /&gt;
 		movlw	0x34			;Timer1&lt;br /&gt;
 		movwf	T1CON			;konfigurieren&lt;br /&gt;
 		movlw	0x1F			;Timer1 laden (für 0,25 s)&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		clrf	TMR1L&lt;br /&gt;
 		bsf	STATUS,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	STATUS,RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		retfie				;erlaube interrupts und springe zurück zu Main&lt;br /&gt;
 CopyDC  	movf	D0,0&lt;br /&gt;
 		movwf	C0&lt;br /&gt;
 		movf	D1,0&lt;br /&gt;
 		movwf	C1&lt;br /&gt;
 		movf	D2,0&lt;br /&gt;
 		movwf	C2&lt;br /&gt;
 		movf	D3,0&lt;br /&gt;
 		movwf	C3&lt;br /&gt;
 		return&lt;br /&gt;
 Init		clrf	PORTA			;Ports löschen &lt;br /&gt;
 		clrf	PORTB&lt;br /&gt;
                 clrf    PORTC&lt;br /&gt;
 		movlw	0x20			;RAM (20-7Fh) löschen&lt;br /&gt;
 		movwf	FSR&lt;br /&gt;
 		clrf	INDF&lt;br /&gt;
 		incf	FSR,1&lt;br /&gt;
 		btfss	FSR,7&lt;br /&gt;
 		goto	$-3     &lt;br /&gt;
 		clrf	ADCON0			;schalte ADC off&lt;br /&gt;
 		movlw	7			;sperre ADC&lt;br /&gt;
 		movwf	ADCON1			;und definiere RA0-7 als digitale I/Os&lt;br /&gt;
 		movlw	0xE0			;GIE, PEIE &amp;amp; TMR0IE erlauben&lt;br /&gt;
 		movwf	INTCON&lt;br /&gt;
 		bsf	STATUS,RP0		;bank 1&lt;br /&gt;
 		movlw	0xEF			;alle PORTA Pins als Eingänge&lt;br /&gt;
 		movwf	TRISA			;nur TOCKI (A4) als Ausgang&lt;br /&gt;
 		clrf	TRISB			;alle PORTB&lt;br /&gt;
                 clrf    TRISC                   ;und PORTC Pins als Ausgänge&lt;br /&gt;
 		movlw	0xE7			;Takt für Timer0 vom T0CKI Pin&lt;br /&gt;
 		movwf	OPTION_REG		;Timer0 konfigurieren&lt;br /&gt;
 		bsf	PIE1,TMR1IE		;TMR1 interrupt erlauben&lt;br /&gt;
 		bcf	STATUS,RP0		;Bank 0&lt;br /&gt;
 		clrf	TMR0			;Timer0 löschen&lt;br /&gt;
 		movlw	0x34			;Timer1 konfigurieren&lt;br /&gt;
 		movwf	T1CON			;(prescaler 8)&lt;br /&gt;
 		movlw	0x1F			;Timer1 laden (für 0,25 s)&lt;br /&gt;
 		movwf	TMR1H&lt;br /&gt;
 		clrf	TMR1L&lt;br /&gt;
 		bsf	STATUS,RP0              ;start Timer0&lt;br /&gt;
 		iorlw	0x10&lt;br /&gt;
 		movwf	TRISA                   ;TOCKI Pin (A4) als Eingang&lt;br /&gt;
 		bcf	STATUS,RP0&lt;br /&gt;
 		bsf	T1CON,TMR1ON		;start Timer1&lt;br /&gt;
 		return&lt;br /&gt;
 		end&lt;br /&gt;
&lt;br /&gt;
=== Mausrad ===&lt;br /&gt;
&lt;br /&gt;
Das UP wertet ein Mausrad aus und setzt, je nach Drehrichtug und sein Anschluss an PORT (PORTA,0 und PORTA,1), ein Flag &amp;quot;_Finc&amp;quot; bzw. &amp;quot;_Fdec&amp;quot;, das vor der nächsten Abfrage, gelöscht werden muss. Zum Auswerten werden 3 Register &amp;quot;MausA&amp;quot;, &amp;quot;MausB&amp;quot; und &amp;quot;MausC&amp;quot; benötigt. Als &amp;quot;_Z&amp;quot; wurde &amp;quot;STATUS,Z&amp;quot; definiert. Die Warteschleife &amp;quot;Delay&amp;quot; dient der Entprellung der Kontakte und soll ca. 10ms sein.&lt;br /&gt;
&lt;br /&gt;
In dem UP &amp;quot;Mouse&amp;quot; wird PORTA eigelesen, die alle Bits ausser 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, b.z.w. 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; (10 b.z.w. 20, 01 b.z.w. 31, 02 b.z.w. 32 oder 13 b.z.w. 23) entsprechendes der Drehrichtung Flag &amp;quot;_Finc&amp;quot; b.z.w. &amp;quot;_Fdec&amp;quot; gesetzt. Anschliessend wird zum Aufrufer zurückgesprungen.&lt;br /&gt;
&lt;br /&gt;
Detailierter PAD:&lt;br /&gt;
&lt;br /&gt;
                                       Mouse      V&lt;br /&gt;
                                              PORTA-&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;
                                              PORTA-&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;
                 |                             W-1-&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;
                 |                     |       W-2-&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;
                 |                     |       W-3-&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;
              W-1-&amp;gt;W                   V                    W-1-&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;
              W-2-&amp;gt;W                W-3-&amp;gt;W                  W-2-&amp;gt;W                W-3-&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	PORTA,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	PORTA,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;
=== Handy Display ===&lt;br /&gt;
&lt;br /&gt;
Als Beispiel die Hardware und Testprogram für Nokia 3310/3330 Display: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124669#124669]]&lt;br /&gt;
&lt;br /&gt;
== Hilfsmittel ==&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 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;
Hardware und Testprogramm: [[http://www.roboternetz.de/phpBB2/viewtopic.php?p=124559#124559]]    &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Microcontroller]]&lt;br /&gt;
[[Kategorie:Software]]&lt;br /&gt;
[[Category:PIC]]&lt;/div&gt;</summary>
		<author><name>Andy</name></author>	</entry>

	</feed>