
EINFÜHRUNG
===========

LDmicro erzeugt einen systemspezifischen Code für einige Microchip PIC16
und Atmel AVR Mikroprozessoren. Üblicherweise wird die Software für diese
Prozessoren in Programmsprachen, wie Assembler, C oder BASIC geschrieben.
Ein Programm, welches in einer dieser Sprachen abgefasst ist, enthält
eine Anweisungsliste. Auch sind die diese Sprachen sehr leistungsfähig
und besonders gut geeignet für die Architektur dieser Prozessoren,
welche diese Anweisungsliste intern abarbeiten.

Programme für speicherprogrammierbare Steuerungen (SPS) andererseits,
werden oftmals im Kontaktplan (KOP = ladder logic) geschrieben.
Ein einfaches Programm, könnte wie folgt aussehen:

   ||                                                                    ||
   ||    Xbutton1           Tdon           Rchatter           Yred       ||
 1 ||-------]/[---------[TON 1.000 s]-+-------]/[--------------( )-------||
   ||                                 |                                  ||
   ||    Xbutton2           Tdof      |                                  ||
   ||-------]/[---------[TOF 2.000 s]-+                                  ||
   ||                                                                    ||
   ||                                                                    ||
   ||                                                                    ||
   ||    Rchatter            Ton             Tneu           Rchatter     ||
 2 ||-------]/[---------[TON 1.000 s]----[TOF 1.000 s]---------( )-------||
   ||                                                                    ||
   ||                                                                    ||
   ||                                                                    ||
   ||------[END]---------------------------------------------------------||
   ||                                                                    ||
   ||                                                                    ||

 (TON ist eine Anzugsverzögerung, TOF eine Abfallverzögerung.
  Die --] [-- Anweisungen bedeuten Eingänge, die sich ähnlich, wie Relais-
  kontakte  verhalten. Die --( )-- Anweisungen bedeuten Ausgänge, die sich
  ähnlich,  wie Relaisspulen verhalten. Viele gute Bezugsquellen werden für
  KOP im Internet oder sonst wo angeboten; Einzelheiten zu dieser speziellen
  Ausführung werden weiter unten angegeben.)

Einige Unterschiede sind jedoch offensichtlich:

* Das Programm wird in einem grafischen Format dargestellt
  und nicht mit einer aus Anweisungen bestehenden Textliste. Viele
  Anwender werden dies zunächst als besser verständlich auffassen.

* Diese Programme erscheinen wie einfachste Schaltpläne, mit
  Relaiskontakten (Eingängen) and Spulen (Ausgängen). Dies ist recht
  intuitiv für Programmierer, die über Kenntnisse der Theorie von
  Elektroschaltplänen verfügen.

* Der ‘ladder logic compiler’ übernimmt was wo berechnet wird.
  Es ist nicht notwendig einen Code zu schreiben, um zu errechnen, wann
  der Status (Zustand) der Ausgänge neu bestimmt werden muss, z.B. auf
  Grund einer Änderung eines Eingangs oder Timers. Auch braucht man die
  Reihenfolge der Berechnungen nicht anzugeben; die SPS-Hilfsprogramme
  übernehmen dies.

LDmicro kompiliert ‘ladder logic’ (KOP) in PIC16- oder AVR-Code.
Die folgenden Prozessoren werden unterstützt:

    * PIC16F877
    * PIC16F628
    * PIC16F876 (ungetestet)
    * PIC16F88 (ungetestet)
    * PIC16F819 (ungetestet)
    * PIC16F887 (ungetestet)
    * PIC16F886 (ungetestet)
    * ATmega8 (ungetestet)
    * ATmega16 (ungetestet)
    * ATmega32 (ungetestet)
    * ATmega128
    * ATmega64
    * ATmega162 (ungetestet)

Es wäre einfach noch weitere AVR- oder PIC16-Prozessoren zu unterstützen,
aber ich habe keine Möglichkeit diese zu testen. Falls Sie einen
bestimmten benötigen, so nehmen Sie Kontakt mit mir auf und ich werde
sehen, was ich tun kann.

Mit LDmicro können Sie ein Kontaktplan-Programm zeichnen bzw. entwickeln.
Auch können Sie dies in Realzeit mit Ihrem Computer simulieren. Wenn
Sie dann überzeugt sind, dass Ihr Programm korrekt ist, so können
Sie die Pins, entsprechend dem Programm als Ein- oder Ausgänge, dem
Mikroprozessor zuweisen. Nach der Zuweisung der Pins können Sie den PIC-
oder AVR-Code für Ihr Programm kompilieren. Der Compiler erzeugt eine
Hex-Datei, mit dem Sie dann Ihren Mikroprozessor programmieren. Dies
ist mit jedem PIC/AVR-Programmer möglich.

LDmicro wurde entworfen, um in etwa mit den meisten kommerziellen
SPS-Systemen ähnlich zu sein. Es gibt einige Ausnahmen und viele Dinge
sind ohnehin kein Standard in der Industrie. Lesen Sie aufmerksam die
Beschreibung jeder Anweisung, auch wenn Ihnen diese vertraut erscheint.
Dieses Dokument setzt ein Grundwissen an Kontaktplan-Programmierung
und der Struktur von SPS-Software voraus (wie: der Ausführungszyklus,
Eingänge lesen, rechnen und Ausgänge setzen).


WEITERE ZIELE
=============

Es ist auch möglich einen ANSI C - Code zu erzeugen. Diesen können
Sie dann für jeden Prozessor verwenden, für den Sie einen C-Compiler
besitzen. Sie sind dann aber selbst verantwortlich, den Ablauf zu
bestimmen. Das heißt, LDmicro erzeugt nur ein Stammprogramm für einen
Funktions- SPS-Zyklus. Sie müssen den SPS-Zyklus bei jedem Durchlauf
aufrufen und auch die Ausführung (Implementierung) der E/A-Funktionen,
die der SPS-Zyklus abruft (wie: lesen/schreiben, digitaler Eingang usw.).
Für mehr Einzelheiten: Siehe die Kommentare in dem erzeugten Quellcode.

Ganz zuletzt kann LDmicro auch für eine virtuelle Maschine einen
prozessor-unabhängigen Byte-Code erzeugen, welche mit der KOP-Kodierung
(ladder logic) laufen soll. Ich habe eine Beispiel-Anwendung des
VM/Interpreters vorgesehen, in ziemlich gutem C geschrieben. Dieses
Anwendungsziel wird halbwegs auf jeder Plattform funktionieren, so lange
Sie Ihre eigene VM vorsehen. Dies könnte für solche Anwendungen nützlich
sein, für die Sie KOP (ladder logic) als Datentransfer-Sprache verwenden
möchten, um ein größeres Programm anzupassen.  Für weitere Einzelheiten:
Siehe die Kommentare in dem Beispiel-Interpreter.


OPTIONEN DER BEFEHLSZEILEN
==========================

ldmicro.exe läuft normalerweise ohne eine Befehlszeilen-Option.
Das heißt, dass Sie nur ein Tastenkürzel zu dem Programm benötigen
oder es auf dem Desktop abspeichern und dann auf das Symbol (die Ikone)
doppelklicken, um es laufen zu lassen. Danach können Sie alles ausführen,
was das GUI (Graphical User Interface) zulässt.

Wenn man an LDmicro einen alleinstehenden Dateinamen in der Befehlszeile
vergeben hat (z. B. ‘ldmicro.exe asd.ld’), wird LDmicro versuchen ‘asd.ld’
zu öffnen, falls diese existiert. Dies bedeutet, dass man ldmicro.exe
mit .ld Dateien verbinden kann, sodass dies automatisch abläuft, wenn
man auf eine .ld Datei doppelklickt.

Wenn man an LDmicro das Argument in der Befehlszeile in folgender Form
vergeben hat: ‘ldmicro.exe /c src.ld dest.hex’, so wird es versuchen
‘src.ld’ zu kompilieren und unter ‘dest.hex’ abzuspeichern. LDmicro endet
nach dem Kompilieren, unabhängig davon, ob die Kompilierung erfolgreich
war oder nicht. Alle Meldungen werden auf der Konsole ausgegeben. Dieser
Modus ist hilfreich, wenn man LDmicro von der Befehlszeile laufen
aus lässt.


GRUNDLAGEN
==========

Wenn Sie LDmicro ohne Argumente aufrufen, so beginnt es als ein leeres
Programm. Wenn Sie LDmicro mit dem Namen eines ‘ladder’ (KOP)-Programms
(z.B. xxx.ld) in der Befehlszeile öffnen, dann wird es versuchen dieses
Programm am Anfang zu laden.

LDmicro verwendet sein eigenes internes Format für das Programm und
man kann kein logisches Zeichen aus einem anderen (Fremd-)Programm
importieren.

Falls Sie nicht ein schon vorhandenes Programm laden, dann wird Ihnen
ein Programm mit einem leeren Netzwerk geliefert. In dieses können Sie
einen Befehl einfügen; z. B. könnten Sie auch eine Reihe von Kontakten
einfügen (Anweisung -> Kontakte Einfügen), die zunächst mit ‘Xneu’
bezeichnet werden. ‘X’ bedeutet, dass der Kontakt auf einen Eingang
des Mikroprozessors festgelegt ist. Diesen Pin können Sie später zuweisen,
nachdem Sie den Mikroprozessor gewählt haben und die Kontakte
umbenannt haben. Der erste Buchstabe zeigt an, um welche Art Objekt es
sich handelt. Zum Beispiel:

    * XName -- Auf einen Eingang des Mikroprozessors festgelegt
    * YName -- Auf einen Ausgang des Mikroprozessors festgelegt
    * RName -- Merker: Ein Bit im Speicher (Internes Relais)
    * TName -- Ein Timer; Anzugs- oder Abfallverzögerung
    * CName -- Ein Zähler, Aufwärts- oder Abwärtszähler
    * AName -- Eine Ganzzahl, von einem A/D-Wandler eingelesen
    * Name  -- Eine Allzweck-Variable als Ganzzahl

Wählen Sie den Rest des Namens, sodass dieser beschreibt, was das Objekt
bewirkt und das dieser auch einmalig im Programm ist. Der gleiche Name
bezieht sich immer auf das gleiche Objekt im Programm. Es wäre zum
Beispiel falsch eine Anzugsverzögerung (TON) ‘TVerzög’ zu nennen und im
selben Programm eine Abfallverzögerung ‘TVerzög’ (TOF), weil jeder Zähler
(oder Timer) seinen eigenen Speicher benötigt. Andererseits wäre es
korrekt einen „Speichernden Timer“ (RTO) ‘TVerzög’ zu nennen und eine
entsprechende Rücksetz-Anweisung (RES)  =  ‘TVerzög’, weil in diesem
Fall beide Befehle dem gleichen Timer gelten.

Die Namen von Variablen können aus Buchstaben, Zahlen und Unter-
strichen (_) bestehen. Der Name einer Variablen darf nicht mit einer
Nummer beginnen. Die Namen von Variablen sind fallabhängig.

Ein Befehl für eine gewöhnliche Variable (MOV, ADD, EQU, usw.), kann
mit Variablen mit jedem Namen arbeiten. Das bedeutet, dass diese Zugang
zu den Timer- und Zähler-Akkumulatoren haben. Das kann manchmal recht
hilfreich sein; zum Beispiel kann man damit prüfen, ob die Zählung eines
Timers in einem bestimmten Bereich liegt.

Die Variablen sind immer 16-Bit Ganzzahlen. Das heißt sie können von
-32768 bis 32767 reichen. Die Variablen werden immer als vorzeichen-
behaftet behandelt. Sie können auch Buchstaben als Dezimalzahlen festlegen
(0, 1234, -56).  Auch können Sie ASCII-Zeichenwerte (‘A’, ‘z’) festlegen,
indem Sie die Zeichen in „Auslassungszeichen“ einfügen. Sie können
ein ASCII-Zeichen an den meisten Stellen verwenden, an denen Sie eine
Dezimalzahl verwenden können.

Am unteren Ende der Maske (Bildanzeige) sehen Sie eine Liste aller
Objekte (Anweisungen, Befehle) des Programms. Diese Liste wird vom
Programm automatisch erzeugt; es besteht somit keine Notwendigkeit diese
von Hand auf dem Laufenden zu halten. Die meisten Objekte benötigen
keine Konfiguration.  ‘XName’, ‘YName’, und ‘AName’  Objekte allerdings,
müssen einem Pin des Mikroprozessors zugeordnet werden. Wählen Sie zuerst
welcher Prozessor verwendet wird (Voreinstellungen -> Prozessor). Danach
legen Sie Ihre E/A Pins fest, indem Sie in der Liste auf diese jeweils
doppelklicken.

Sie können das Programm verändern, indem Sie Anweisungen (Befehle)
einfügen oder löschen. Die Schreibmarke (cursor)im Programm blinkt,
um die momentan gewählte Anweisung und den Einfügungspunkt anzuzeigen.
Falls diese nicht blinkt, so drücken Sie den <Tabulator> oder klicken
Sie auf eine Anweisung. Jetzt können Sie die momentane Anweisung löschen
oder eine neue Anweisung einfügen; links oder rechts (in Reihenschaltung)
oder über oder unter (in Parallelschaltung) mit der gewählten Anweisung.
Einige Handhabungen sind nicht erlaubt, so zum Beispiel weitere
Anweisungen rechts von einer Spule.

Das Programm beginnt mit nur einem Netzwerk. Sie können mehr Netzwerke
hinzufügen, indem Sie ‘Netzwerk Einfügen Davor/Danach’ im Programm-Menü
wählen.  Den gleichen Effekt könnten Sie erzielen, indem Sie viele
komplizierte parallele Unterschaltungen in einem einzigen Netzwerk
unterbringen. Es ist aber übersichtlicher, mehrere Netzwerke zu verwenden.

Wenn Sie Ihr Programm fertig geschrieben haben, so können Sie dieses
mit der Simulation testen. Danach können Sie es in eine Hex-Datei für
den zugedachten Mikroprozessor kompilieren.


SIMULATION
==========

Um den Simulationsbetrieb einzugeben, wählen Sie ‘Simulieren ->
Simulationsbetrieb’ oder drücken Sie <Strg+M>.  Das Programm wird
im Simulationsbetrieb unterschiedlich dargestellt. Es gibt keine
Schreibmarke (cursor) mehr. Die „erregten“ Anweisungen erscheinen hellrot,
die „nicht erregten“ erscheinen grau.  Drücken Sie die Leertaste, um das
SPS-Programm nur einen einzelnen Zyklus durchlaufen zu lassen. Wählen
Sie für einen kontinuierlichen Umlauf in Echtzeit ‘Simulieren -> Start
Echtzeit-Simulation’ oder drücken Sie <Strg+R>. Die Maske (Bildanzeige)
des Programms wird jetzt in Echtzeit, entsprechend der Änderungen des
Status (des Zustands) des Programms aktualisiert.

Sie können den Status (Zustand) eines Eingangs im Programm einstellen,
indem Sie auf den jeweiligen auf der Liste am unteren Ende der
Maske (Bildanzeige) doppelklicken oder auf die jeweilige ‘XName’
Kontakt-Anweisung im Programm. Wenn Sie den Status (Zustand) eines
Eingangs-Pins ändern, so wird diese Änderung nicht unmittelbar in
der Maske (Bildanzeige) wiedergegeben, sondern erst wenn sich die
SPS im zyklischen Umlauf befindet. Das geschieht automatisch wenn das
SPS-Programm in Echtzeit-Simulation läuft, oder wenn Sie die Leertaste
drücken.


KOMPILIEREN ZUM SYSTEMSPEZIFISCHEN CODE
=======================================

Letztlich ist es dann nur sinnvoll eine .hex Datei zu erzeugen, mit
der Sie Ihren Mikroprozessor programmieren können. Zunächst müssen
Sie die Teilenummer des Mikroprozessors im Menü ‘Voreinstellungen ->
Prozessor’ wählen. Danach müssen jedem ‘XName’ oder ‘YName’ Objekt
einen E/A-Pin zuweisen. Tun Sie dies, indem auf den Namen des Objekts
doppelklicken, welcher sich in der Liste ganz unten in der Maske
(Bildanzeige) befindet. Ein Dialogfenster wird dann erscheinen und Sie
können daraufhin einen noch nicht vergebenen Pin von der Liste aussuchen.

Als nächstes müssen Sie die Zykluszeit wählen, mit der Sie das
Programm laufen lassen wollen, auch müssen Sie dem Compiler mitteilen
mit welcher Taktgeschwindigkeit der Prozessor arbeiten soll. Diese
Einstellungen werden im Menü ‘Voreinstellungen -> Prozessor Parameter...’
vorgenommen. Üblicherweise sollten Sie die Zykluszeit nicht ändern,
denn diese ist auf 10ms voreingestellt, dies ist ein guter Wert für
die meisten Anwendungen. Tippen Sie die Frequenz des Quarzes (oder des
Keramik-Resonators) ein, mit der Sie den Prozessor betreiben wollen und
klicken auf Okay.

Jetzt können Sie einen Code von Ihrem Programm erzeugen.  Wählen Sie
‘Kompilieren -> Kompilieren’ oder ‘Kompilieren -> Kompilieren unter...’,
falls Sie vorher Ihr Programm schon kompiliert haben und einen neuen Namen
für die Ausgangsdatei vergeben wollen. Wenn Ihr Programm fehlerfrei ist,
wird LDmicro eine Intel IHEX Datei erzeugen, mit der sich Ihr Prozessor
programmieren lässt.

Verwenden Sie hierzu irgendeine Programmier Soft- und Hardware, die Sie
besitzen, um die Hex-Datei in den Mikroprozessor zu laden.  Beachten Sie
die Einstellungen für die Konfigurationsbits (fuses)!  Bei den PIC16
Prozessoren sind diese Konfigurationsbits bereits in der Hex-Datei
enthalten. Die meisten Programmiersoftwares schauen automatisch nach
diesen. Für die AVR-Prozessoren müssen Sie die Konfigurationsbits von
Hand einstellen.


ANWEISUNGS-VERZEICHNIS
======================

> KONTAKT, SCHLIESSER           XName        RName        YName
                             ----] [----  ----] [----  ----] [----

Wenn ein ‘unwahres’ Signal diese Anweisung erreicht, so ist das
Ausgangssignal ‘unwahr’. Wenn ein ‘wahres’ Signal diese Anweisung
erreicht, so ist das Ausgangssignal ‘wahr’. Dies nur, falls der
vorliegende Eingangspin, Ausgangspin oder eines Merkers (Hilfsrelais)
‘wahr’ ist, anderenfalls ist es unwahr. Diese Anweisung fragt den Status
(Zustand) eines Eingangspins, Ausgangspins oder Merkers (Hilfsrelais) ab.


> KONTAKT, ÖFFNER              XName        RName        YName
                            ----]/[----  ----]/[----  ----]/[----

Wenn ein ‘unwahres’ Signal diese Anweisung erreicht, so ist das
Ausgangssignal ‘unwahr’. Wenn ein ‘wahres’ Signal diese Anweisung
erreicht, so ist das Ausgangssignal ‘wahr’. Dies nur, falls der
vorliegende Eingangspin, Ausgangspin oder der Merker (= internes
Hilfsrelais) ‘unwahr’ ist, anderenfalls ist es ‘unwahr’. Diese Anweisung
fragt den Status (Zustand) eines Eingangspins, Ausgangspins oder Merkers
(Hilfsrelais) ab. Dies ist das Gegenteil eines Schließers.


> SPULE, NORMAL (MERKER,AUSGANG)    RName           YName
                                  ----( )----     ----( )----

Wenn ein ‘unwahres’ Signal diese Anweisung erreicht, so wird der
vorliegende Merker (Hilfsrelais) oder Ausgangspin nicht angesteuert. Wenn
ein ‘wahres’ Signal diese Anweisung erreicht, so wird der vorliegende
Merker (Hilfsrelais) oder Ausgangspin angesteuert. Es ist nicht sinnvoll
dieser Spule eine Eingangsvariable zuzuweisen. Diese Anweisung muss
ganz rechts im Netzwerk stehen.


> SPULE, NEGIERT (MERKER,AUSGANG)   RName          YName
                                  ----(/)----   ----(/)----

Wenn ein ‘wahres’ Signal diese Anweisung erreicht, so wird der vorliegende
Merker (Hilfsrelais)oder Ausgangspin nicht angesteuert. Wenn ein
‘unwahres’ Signal diese Anweisung erreicht, so wird der vorliegende Merker
(Hilfsrelais) oder Ausgangspin angesteuert. Es ist nicht sinnvoll dieser
Spule eine Eingangsvariable zuzuweisen. Dies ist das Gegenteil einer
normalen Spule. Diese Anweisung muss im Netzwerk ganz rechts stehen.


> SPULE, SETZEN      RName           YName
                  ----(S)----     ----(S)----

Wenn ein ‘wahres’ Signal diese Anweisung erreicht, so wird der vorliegende
Merker (Hilfsrelais)oder Ausgangspin auf ‘wahr’ gesetzt. Anderenfalls
bleibt der Status (Zustand) des Merkers (Hilfsrelais) oder Ausgangspins
unverändert.  Diese Anweisung kann nur den Status (Zustand) einer Spule
von ‘unwahr’ nach ‘wahr’ verändern, insofern wird diese üblicherweise in
einer Kombination mit einer Rücksetz-Anweisung für eine Spule verwendet.
Diese Anweisung muss ganz rechts im Netzwerk stehen.


> SPULE, RÜCKSETZEN    RName           YName
                    ----(R)----     ----(R)----

Wenn ein ‘wahres’ Signal diese Anweisung erreicht, so wird der vorliegende
Merker (Hilfsrelais) oder Ausgangspin rückgesetzt. Anderenfalls bleibt der
Status (Zustand) des Merkers (Hilfsrelais) oder Ausgangspins unverändert.
Diese Anweisung kann nur den Status (Zustand) einer Spule von ‘wahr’ nach
‘unwahr’ verändern, insofern wird diese üblicherweise in einer Kombination
mit einer Setz-Anweisung für eine Spule verwendet. Diese Anweisung muss
ganz rechts im Netzwerk stehen.


> ANZUGSVERZÖGERUNG         Tdon
                      -[TON 1.000 s]-

Wenn ein Signal diese Anweisung erreicht, welches seinen Status
(Zustand) von ‘unwahr’ nach ‘wahr’ ändert, so bleibt das Ausgangssignal
für 1,000 s ‘unwahr’, dann wird es ‘wahr’. Wenn ein Signal diese
Anweisung erreicht, welches seinen Status (Zustand) von ‘wahr’ nach
‘unwahr’ ändert, so wird das Ausgangssignal sofort ‘unwahr’. Der Timer
wird jedes Mal rückgesetzt (bzw. auf Null gesetzt), wenn der Eingang
‘unwahr’ wird. Der Eingang muss für 1000 aufeinanderfolgende Millisekunden
‘wahr’ bleiben, bevor auch der Ausgang ‘wahr’ wird. Die Verzögerung
ist konfigurierbar.

Die ‘TName’ Variable zählt, in der Einheit der jeweiligen Zykluszeit,
von Null ab hoch. Der Ausgang der TON-Anweisung wird wahr, wenn die
Zählervariable größer oder gleich der vorliegenden Verzögerung ist.
Es möglich die Zählervariable an einer anderen Stelle im Programm zu
bearbeiten, zum Beispiel mit einer TRANSFER-Anweisung (MOV).


> ABFALLVERZÖGERUNG         Tdoff
                      -[TOF 1.000 s]-

Wenn ein  Signal diese Anweisung erreicht, welches seinen Status
(Zustand) von ‘wahr’ nach ‘unwahr’ ändert, so bleibt das Ausgangssignal
für 1,000 s ‘wahr’, dann wird es ‘unwahr’. Wenn ein Signal diese
Anweisung erreicht, welches seinen Status (Zustand) von ‘unwahr’ nach
‘wahr’ ändert, so wird das Ausgangssignal sofort ‘wahr’. Der Timer wird
jedes Mal rückgesetzt (bzw. auf Null gesetzt), wenn der Eingang ‘unwahr’
wird. Der Eingang muss für 1000 aufeinanderfolgende Millisekunden ‘unwahr’
bleiben, bevor auch der Ausgang ‘unwahr’ wird. Die Verzögerung ist
konfigurierbar.

Die ‘TName’ Variable zählt, in der Einheit der jeweiligen Zykluszeit,
von Null ab hoch. Der Ausgang der TOF Anweisung wird wahr, wenn die
Zählervariable größer oder gleich der vorliegenden Verzögerung ist.
Es möglich die Zählervariable an einer anderen Stelle im Programm zu
bearbeiten, zum Beispiel mit einer TRANSFER-Anweisung (MOV).


> SPEICHERNDER TIMER         Trto
                      -[RTO 1.000 s]-

Diese Anweisung zeichnet auf, wie lange sein Eingang ‘wahr’ gewesen
ist. Wenn der Eingang für mindestens 1.000 s ‘wahr’ gewesen ist, dann
wird der Ausgang ‘wahr’. Andernfalls ist er ‘unwahr’. Der Eingang muss
für 1000 aufeinanderfolgende Millisekunden ‘wahr’ gewesen sein; wenn
der Eingang für 0,6 s ‘wahr’ war, dann ‘unwahr’ für 2,0 s und danach für
0,4 s  wieder ‘wahr’, so wird sein Ausgang ‘wahr’. Nachdem der Ausgang
‘wahr’ wurde, so bleibt er ‘wahr’, selbst wenn der Eingang ‘unwahr’
wird, so lange der Eingang für länger als 1.000 s ‘wahr’ gewesen ist.
Der Timer muss deshalb von Hand mit Hilfe der Rücksetz-Anweisung
rückgesetzt (auf Null gesetzt) werden.

Die ‘TName’ Variable zählt, in der Einheit der jeweiligen Zykluszeit,
von Null ab hoch. Der Ausgang der RTO-Anweisung wird wahr, wenn die
Zählervariable größer oder gleich der vorliegenden Verzögerung ist.
Es möglich die Zählervariable an einer anderen Stelle im Programm zu
bearbeiten, zum Beispiel mit einer TRANSFER-Anweisung (MOV).


> RÜCKSETZEN              Trto             Citems
                     ----{RES}----     ----{RES}----

Diese Anweisung rücksetzt einen Timer oder Zähler. TON oder TOF Timer
werden automatisch rückgesetzt, wenn ihr Eingang ‘wahr’ oder ‘unwahr’
wird, somit ist die RES-Anweisung für diese Timer nicht erforderlich. RTO
Timer und CTU/CTD Zähler werden nicht automatisch rückgesetzt, somit
müssen diese von Hand mit Hilfe der RES-Anweisung rückgesetzt (auf Null)
werden. Wenn der Eingang ‘wahr’ ist, so wird der Timer oder Zähler
rückgesetzt; wenn der Eingang ‘unwahr’ ist, so erfolgt keine Aktion.
Diese Anweisung muss ganz rechts im Netzwerk stehen.

                                            _    _
> ONE-SHOT RISING, STEIGENDE FLANKE    --[_/ OSR/ \_]--

Diese Anweisung wird normalerweise ‘unwahr’ ausgewiesen. Wenn der Eingang
der Anweisung während des momentanen Zyklus ‘wahr’ ist und während des
vorgehenden ‘unwahr’ war, so wird der Ausgang ‘wahr’. Daher erzeugt diese
Anweisung bei jeder steigenden Flanke einen Impuls für einen Zyklus.
Diese Anweisung ist hilfreich, wenn Sie Ereignisse an der steigenden
Flanke eines Signals auslösen wollen.

                                          _      _
> ONE-SHOT FALLING, FALLENDE FLANKE    --[ \_OSF/ \_]--

Diese Anweisung wird normalerweise ‘unwahr’ ausgewiesen. Wenn der Eingang
der Anweisung während des momentanen Zyklus ‘unwahr’ ist und während des
vorgehenden ‘wahr’ war, so wird der Ausgang ‘wahr’. Daher erzeugt diese
Anweisung bei jeder fallenden Flanke einen Impuls für einen Zyklus.
Diese Anweisung ist hilfreich, wenn Sie Ereignisse an der fallenden
Flanke eines Signals auslösen wollen.


> BRÜCKE, ÖFFNUNG     ----+----+----      ----+     +----

Der Eingangszustand einer Brücke ist immer gleich seinem Ausgangszustand.
Der Ausgangszustands einer Öffnung ist immer ‘unwahr’. Diese Anweisungen
sind bei der Fehlerbehebung (debugging) besonders hilfreich.


> MASTER CONTROL RELAIS   -{MASTER RLY}-


Im Normalfall ist der Anfang (die linke Stromschiene) von jedem Netzwerk
‘wahr’. Wenn eine ‘Master Control Relais’ Anweisung ausgeführt wird dessen
Eingang ‘unwahr’ ist, so werden die Anfänge (die linke Stromschiene)
aller folgenden Netzwerke ‘unwahr’. Das setzt sich fort bis die nächste
‘Master Control Relais’ Anweisung erreicht wird (unabhängig von dem
Anfangszustand dieser Anweisung). Diese Anweisungen müssen daher als Paar
verwendet werden: Eine (vielleicht abhängige), um den „gegebenenfalls
gesperrten“ Abschnitt zu starten und eine weitere, um diesen zu beenden.


> TRANSFER, MOV           {destvar :=  }      {Tret :=     }
                         -{ 123     MOV}-    -{ srcvar  MOV}-

Wenn der Eingang dieser Anweisung ‘wahr’ ist, so setzt diese die
vorliegende Zielvariable gleich der vorliegenden Quellvariablen
oder Konstanten. Wenn der Eingang dieser Anweisung ‘unwahr’ ist, so
geschieht nichts. Mit der TRANSFER-Anweisung (MOV) können Sie jede
Variable zuweisen; dies schließt Timer und Zähler Statusvariablen ein,
welche mit einem vorgestellten ‘T’ oder ‘C’ unterschieden werden. Eine
Anweisung zum Beispiel, die eine ‘0’ in einen ‘TBewahrend’ transferiert,
ist äquivalent mit einer RES-Anweisung für diesen Timer. Diese Anweisung
muss ganz rechts im Netzwerk stehen.


> ARITHMETISCHE OPERATIONEN   {ADD  kay  :=}       {SUB  Ccnt :=}
                             -{ 'a' + 10   }-     -{ Ccnt - 10  }-

>                             {MUL  dest :=}       {DIV  dv :=  }
                             -{ var * -990 }-     -{ dv / -10000}-

Wenn der Eingang einer dieser Anweisungen ‘wahr’ ist, so setzt diese
die vorliegende Zielvariable gleich dem vorliegenden arithmetischem
Ausdruck. Die Operanden können entweder Variabelen (einschließlich Timer-
und Zählervariabelen) oder Konstanten sein. Diese Anweisungen verwenden
16-Bitzeichen Mathematik. Beachten Sie, dass das Ergebnis jeden Zyklus
ausgewertet wird, wenn der Eingangszustand ‘wahr’ ist. Falls Sie eine
Variable inkrementieren oder dekrementieren (d.h., wenn die Zielvariable
ebenfalls einer der Operanden ist), dann wollen Sie dies vermutlich
nicht; normalerweise würden Sie einen Impuls (one-shot) verwenden,
sodass die Variable nur bei einer steigenden oder fallenden Flanke des
Eingangszustands ausgewertet wird. Dividieren kürzt: D.h. 8 / 3 = 2.
Diese Anweisungen müssen ganz rechts im Netzwerk stehen.


> VERGLEICHEN           [var ==]        [var >]        [1 >=]
                       -[ var2 ]-      -[ 1   ]-      -[ Ton]-

>                       [var !=]        [-4 <   ]      [1 <=]
                       -[ var2 ]-      -[ vartwo]-    -[ Cup]-

Wenn der Eingang dieser Anweisung ‘unwahr’ ist, so ist der Ausgang
auch ‘unwahr’. Wenn der Eingang dieser Anweisung ‘wahr’ ist, dann ist
Ausgang ‘wahr’; dies aber nur, wenn die vorliegende Bedingung ‘wahr’
ist. Diese Anweisungen können zum Vergleichen verwendet werden, wie:
Auf gleich, auf größer als, auf größer als oder gleich, auf ungleich,
auf kleiner als, auf kleiner als oder gleich, eine Variable mit einer
Variablen oder eine Variable mit einer 16-Bitzeichen-Konstanten.


> ZÄHLER        CName          CName
              --[CTU >= 5]--  --[CTD > -5]--

Ein Zähler inkrementiert (CTU, aufwärtszählen) oder dekrementiert
(CTD, abwärtszählen) die bezogene Zählung bei jeder steigenden Flanke
des Eingangszustands des Netzwerks (d.h. der Eingangszustand des
Netzwerks geht von ‘unwahr’ auf ‘wahr’ über).  Der Ausgangszustand des
Zählers ist ‘wahr’, wenn die Zähler- variable ist größer oder gleich 5
und andernfalls ‘unwahr’. Der Ausgangszustand des Netzwerks kann ‘wahr’
sein, selbst wenn der Eingangszustand ‘unwahr’ ist; das hängt lediglich
von Zählervariablen ab. Sie können einer CTU- und CTD-Anweisung den
gleichen Namen zuteilen, um den gleichen Zähler zu inkrementieren und
dekrementieren. Die RES-Anweisung kann einen Zähler rücksetzen oder auch
eine gewöhnliche Variablen-Operation mit der Zählervariablen ausführen.


> ZIRKULIERENDER ZÄHLER       CName
                          --{CTC 0:7}--

Ein zirkulierender Zähler arbeitet wie ein normaler CTU-Zähler, außer
nach der Erreichung seiner Obergrenze, rücksetzt er seine Zählervariable
auf Null. Zum Beispiel würde der oben gezeigte Zähler, wie folgt zählen:
0, 1, 2, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2,....  Dies ist
hilfreich in Kombination mit bedingten Anweisungen der Variablen‘CName’;
Sie können dies als eine Folgeschaltung verwenden. CTC-Zähler takten
mit der aufsteigenden Flanke der Eingangsbedingung des Netzwerks.
Diese Anweisung muss ganz rechts im Netzwerk stehen.


> SCHIEBEREGISTER          {SHIFT REG   }
                          -{ reg0..3    }-

Ein Schieberegister besteht aus einer Reihe von Variablen. So bestünde
zum Beispiel ein Schieberegister aus den Variablen ‘reg0’, ‘reg1’,
‘reg2’, and ‘reg3’. Der Eingang des Schieberegisters ist ‘reg0’. Bei
jeder steigenden Flanke der Eingansbedingung des Netzwerks, schiebt das
Schieberegister nach rechts. Dies bedeutet es wie folgt zuweist: ‘reg3’
nach ‘reg2’, ‘reg2’ nach ‘reg1’ und ‘reg1’ nach ‘reg0’.  ‘reg0’ bleibt
unverändert. Ein großes Schieberegister kann leicht viel Speicherplatz
belegen. Diese Anweisung muss ganz rechts im Netzwerk stehen.


> NACHSCHLAG-TABELLE       {dest :=     }
                          -{ LUT[i]     }-

Eine Nachschlag-Tabelle ist eine Anordnung von n Werten. Wenn die
Eingangsbedingung des Netzwerks ‘wahr’ ist, so wird die Ganzzahl-Variable
‘dest’ mit dem Eintrag in der Nachschlag-Tabelle gleichgesetzt, der der
Ganzzahl-Variablen ‘i’ entspricht. Das Verzeichnis beginnt bei Null,
insofern muss sich ‘i’ zwischen 0 und (n-1) befinden. Das Verhalten
dieser Anweisung ist undefiniert, wenn sich die Werte des Verzeichnisses
außerhalb dieses Bereichs befinden.


> NÄHERUNGS-LINEAR-TABELLE    {yvar :=}
                             -{PWL[xvar] }-

Dies ist eine gute Methode für die Näherungslösung einer komplizierten
Funktion oder Kurve. Sie könnte zum Beispiel hilfreich sein, wenn Sie
versuchen eine Eichkurve zu verwenden, um die rohe Ausgangsspannung
eines Fühlers in günstigere Einheiten zu wandeln.

Angenommen Sie versuchen eine Näherungslösung für eine Funktion zu finden,
die eine Eingangs-Ganzzahlvariable ‘x’ in Ausgangs-Ganzzahlvariable ‘y’
wandelt. Einige Punkte der Funktion sind Ihnen bekannt; so würden Sie
z.B. die folgenden kennen:

    f(0)     = 2
    f(5)     = 10
    f(10)     = 50
    f(100) = 100

Dies bedeutet, dass sich die Punkte

    (x0, y0)    = (  0,    2)
    (x1, y1)    = (  5,   10)
    (x2, y2)    = ( 10,   50)
    (x3, y3)    = (100,  100)

in dieser Kurve befinden. Diese 4 Punkte können Sie in die Tabelle der
‘Näherungs-Linear’-Anweisung eintragen. Die ‘Näherungs-Linear’-Anweisung
wird dann auf den Wert von ‘xvar’ schauen und legt den Wert von ‘yvar’
fest. Sie stellt ‘yvar’ so ein, dass die ‘Näherungs-Linear’-Kurve sich
durch alle Punkte bewegt, die Sie vorgegeben haben.  Wenn Sie z.B. für
‘xvar’ = 10 vorgegeben haben, dann stellt die Anweisung ‘yvar’ auf gleich
50 ein.

Falls Sie dieser Anweisung einen Wert ‘xvar’ zuweisen, der zwischen zwei
Werten von ‘x’ liegt, denen Sie Punkte zugeordnet haben, dann stellt die
Anweisung ‘yvar’ so ein, dass (‘xvar’, ‘yvar’) in der geraden Linie liegt;
diejenige die, die zwei Punkte in der Tabelle verbindet. Z.B. erzeugt
‘xvar’ = 55 bei ‘yvar’ = 75. Die beiden Punkte in der Tabelle sind (10,
50) und (100, 100). 55 liegt auf halbem Weg zwischen 10 und 100 und 75
liegt auf halbem Weg zwischen 50 und 100, somit liegt (55, 75) auf der
Linie, die diese zwei Punkte verbindet.

Die Punkte müssen in aufsteigender Reihenfolge der x-Koordinaten
angegeben werden. Einige mathematische Operationen, erforderlich für
bestimmte Nachschlag-Tabellen mit 16-Bit-Mathematik, kann man ggf. nicht
ausführen. In diesem Falle gibt LDmicro eine Warnmeldung aus. So würde
z.B. die folgende Nachschlag-Tabelle eine Fehlermeldung hervorrufen:

    (x0, y0)    = (  0,    0)
    (x1, y1)    = (300,  300)

Sie können diesen Fehler beheben, indem sie den Abstand zwischen den
Punkten kleiner machen. So ist zum Beispiel die nächste Tabelle äquivalent
zur vorhergehenden, ruft aber keine Fehlermeldung hervor.

    (x0, y0)    = (  0,    2)
    (x1, y1)    = (150,  150)
    (x2, y2)    = (300,  300)

Es wird kaum einmal notwendig sein, mehr als fünf oder sechs Punkte
zu verwenden. Falls Sie mehr Punkte hinzufügen, so vergrößert dies
Ihren Code und verlangsamt die Ausführung. Falls Sie für ‘xvar’ einen
Wert vergeben, der größer ist, als die größte x-Koordinate der Tabelle
oder kleiner, als die kleinste x-Koordinate in der Tabelle, so ist das
Verhalten der Anweisung undefiniert. Diese Anweisung muss ganz rechts
im Netzwerk stehen.


> A/D-WANDLER EINLESEN      AName
                        --{READ ADC}--

LDmicro kann einen Code erzeugen, der ermöglicht, die A/D-Wandler
zu verwenden, die in manchen Mikroprozessoren vorgesehen sind.
Wenn der Eingangszustand dieser Anweisung ‘wahr’ ist, dann wird eine
Einzellesung von dem A/D-Wandler entnommen und in der Variablen ‘AName’
gespeichert. Diese Variable kann anschließend mit einer gewöhnlichen
Ganzzahlvariablen bearbeitet werden (wie: Kleiner als, größer als,
arithmetisch usw.). Weisen Sie ‘Axxx’ in der gleichen Weise einen Pin
zu, wie Sie einen Pin für einen digitalen Ein- oder Ausgang vergeben
würden, indem auf diesen in der Liste unten in der Maske (Bildanzeige)
doppelklicken.  Wenn der Eingangszustand dieses Netzwerks ‘unwahr’ ist,
so wird die Variable ‘AName’ unverändert belassen.

Für alle derzeitig unterstützten Prozessoren gilt: Eine 0 Volt Lesung
am Eingang des A/D-Wandlers entspricht 0. Eine Lesung gleich der
Versorgungsspannung (bzw. Referenzspannung) entspricht 1023. Falls Sie
AVR-Prozessoren verwenden, so verbinden Sie AREF mit Vdd.  (Siehe Atmel
Datenblatt, dort wird eine Induktivität von 100µH empfohlen). Sie können
arithmetische Operationen verwenden, um einen günstigeren Maßstabfaktor
festzulegen, aber beachten Sie, dass das Programm nur Ganzzahl-Arithmetik
vorsieht. Allgemein sind nicht alle Pins als A/D-Wandler verwendbar. Die
Software gestattet Ihnen nicht, einen Pin zuzuweisen, der kein A/D
bzw. analoger Eingang ist. Diese Anweisung muss ganz rechts im Netzwerk
stehen.


> PULSWEITEN MODULATIONSZYKLUS FESTLEGEN    duty_cycle
                                          -{PWM 32.8 kHz}-

LDmicro kann einen Code erzeugen, der ermöglicht, die PWM-Peripherie
zu verwenden, die in manchen Mikroprozessoren vorgesehen ist. Wenn die
Eingangsbedingung dieser Anweisung ‘wahr’ ist, so wird der Zyklus der
PWM-Peripherie mit dem Wert der Variablen ‘duty cycle’ gleichgesetzt. Der
‘duty cycle’ muss eine Zahl zwischen 0 und 100 sein. 0 entspricht immer
‘low’ und 100 entsprechend  immer ‘high’. (Wenn Sie damit vertraut sind,
wie die PWM-Peripherie funktioniert, so bemerken Sie, dass dies bedeutet,
dass LDmicro die ‘duty cycle’-Variable automatisch prozentual zu den
PWM-Taktintervallen skaliert [= den Maßstabfaktor festlegt].)

Sie können die PWM-Zielfrequenz in Hz definieren. Es kann vorkommen, dass
die angegebene Frequenz nicht genau erreicht wird, das hängt davon ab,
wie sich diese innerhalb der Taktfrequenz des Prozessors einteilt. LDmicro
wählt dann die nächst erreichbare Frequenz; falls der Fehler zu groß ist,
so wird eine Warnung ausgegeben. Höhere Geschwindigkeiten können die
Auflösung beeinträchtigen.

Diese Anweisung muss ganz rechts im Netzwerk stehen. Die ‘ladder
logic’-Laufzeit verbraucht (schon) einen Timer, um die Zykluszeit
zu messen. Dies bedeutet, dass die PWM nur bei den Mikroprozessoren
verfügbar ist, bei denen mindestens zwei geeignete Timer vorhanden sind.
PWM verwendet den PIN CCP2 (nicht CCP1) bei den PIC16-Prozessoren und
OC2 (nicht OC1A) bei den AVR-Prozessoren.


> REMANENT MACHEN     saved_var
                    --{PERSIST}--

Wenn der Eingangszustand dieser Anweisung ‘wahr’ ist, so bewirkt
dies, dass eine angegebene Ganzzahl-Variable automatisch im EEPROM
gespeichert wird. Dies bedeutet, dass ihr Wert bestehen bleiben wird,
auch wenn der Prozessor seine Versorgungsspannung verliert. Es ist
nicht notwendig, die Variable an klarer Stelle im EEPROM zu speichern,
dies geschieht automatisch, so oft sich der Wert der Variablen
ändert. Bei Spannungswiederkehr wird die Variable automatisch vom
EEPROM zurückgespeichert. Falls eine Variable, die häufig ihren Wert
ändert, remanent (dauerhaft) gemacht wird, so könnte Ihr Prozessor sehr
rasch verschleißen, weil dieser lediglich für eine begrenzte Anzahl von
Schreibbefehlen konstruiert ist (~100 000). Wenn der Eingangszustand des
Netzwerks ‘unwahr’ ist, so geschieht nichts. Diese Anweisung muss ganz
rechts im Netzwerk stehen.


> UART (SERIELL) EMPFANGEN      var
                            --{UART RECV}--

LDmicro kann einen Code erzeugen, der ermöglicht UART zu verwenden,
welcher in manchen Mikroprozessoren vorgesehen ist.
Bei AVR-Prozessoren mir mehrfachem UART, wird nur UART1 (nicht UART0)
unterstützt. Konfigurieren Sie die Baudrate, indem Sie ‘Voreinstellungen
-> Prozessor-Parameter’ verwenden. Bestimmte Baudraten werden mit
bestimmten Quarzfrequenzen nicht erreichbar sein. In diesem Fall gibt
LDmicro eine Warnmeldung.

Wenn der Eingangszustand dieser Anweisung ‘unwahr’ ist, so geschieht
nichts. Wenn der Eingangszustand ‘wahr’ ist, so versucht diese Anweisung
ein einzelnes Schriftzeichen vom UART-Eingang zu empfangen. Wenn
kein Schriftzeichen eingelesen wird, dann ist der Ausgangszustand
‘unwahr’. Wenn ein ASCII-Zeichen eingelesen wird, so wird sein Wert in
‘var’ abgespeichert und der Ausgangszustand wird für einen einzelnen
Zyklus ‘wahr’.


> UART (SERIELL) SENDEN       var
                          --{UART SEND}--

LDmicro kann einen Code erzeugen, der ermöglicht UART zu verwenden,
welcher in manchen Mikroprozessoren vorgesehen ist.
Bei AVR-Prozessoren mir mehrfachem UART, wird nur UART1 (nicht UART0)
unterstützt. Konfigurieren Sie die Baudrate, indem Sie ‘Voreinstellungen
-> Prozessor-Parameter’ verwenden. Bestimmte Baudraten werden mit
bestimmten Quarzfrequenzen nicht erreichbar sein. In diesem Fall gibt
LDmicro eine Warnmeldung.

Wenn der Eingangszustand dieser Anweisung ‘unwahr’ ist, so geschieht
nichts. Wenn der Eingangszustand ‘wahr’ ist, so schreibt diese
Anweisung ein einzelnes Schriftzeichen zum UART. Der ASCII-Wert des
Schriftzeichens, welches gesendet werden soll, muss vorher in ‘var’
abgespeichert worden sein. Der Ausgangszustand dieses Netzwerks ist
‘wahr’, wenn UART beschäftigt ist (gerade dabei ein Schriftzeichen zu
übermitteln) und andernfalls ‘unwahr’.

Denken Sie daran, dass einige Zeit zum Senden von Schriftzeichen
beansprucht wird. Überprüfen Sie den Ausgangszustand dieser Anweisung,
sodass das erste Schriftzeichen bereits übermittelt wurde, bevor Sie
versuchen ein zweites Schriftzeichen zu übermitteln. Oder verwenden Sie
einen Timer, um eine Verzögerung zwischen die Schriftzeichen fügen. Sie
dürfen den Eingangszustand dieser Anweisung nur dann auf ‘wahr’ setzen
(bzw. ein Schriftzeichen übermitteln), wenn der Ausgangszustand ‘unwahr’
ist (bzw. UART unbeschäftigt ist).

Untersuchen Sie die “Formatierte Zeichenfolge”-Anweisung, bevor Sie
diese Anweisung verwenden. Die “Formatierte Zeichenfolge”- Anweisung
ist viel einfacher in der Anwendung und fast sicher fähig, das zu tun,
was Sie beabsichtigen.


> FORMATIERTE ZEICHENFOLGE ÜBER UART            var
                                        -{"Druck: \3\r\n"}-

LDmicro kann einen Code erzeugen, der ermöglicht UART zu verwenden,
welcher in manchen Mikroprozessoren vorgesehen ist.
Bei AVR-Prozessoren mir mehrfachem UART, wird nur UART1 (nicht UART0)
unterstützt. Konfigurieren Sie die Baudrate, indem Sie ‘Voreinstellungen
-> Prozessor-Parameter’ verwenden. Bestimmte Baudraten werden mit
bestimmten Quarzfrequenzen nicht erreichbar sein. In diesem Fall gibt
LDmicro eine Warnmeldung.

Wenn der Eingangszustand des Netzwerks für diese Anweisung von ‘unwahr’
auf ‘wahr’ übergeht, so beginnt diese eine vollständige Zeichenfolge
über den seriellen Anschluss zu senden. Wenn die Zeichenfolge die
besondere Reihenfolge ‘\3’ enthält, dann wird diese Folge durch den Wert
von ‘var’ ersetzt, welcher automatisch in eine Zeichenfolge gewandelt
wird. Die Variable wird formatiert, sodass diese exakt 3 Schriftzeichen
übernimmt. Falls die Variable zum Beispiel gleich 35 ist, dann wird die
exakte ausgegebene Zeichenfolge, wie folgt aussehen: ‘Druck:  35\r\n’
(beachten Sie das zusätzliche Freizeichen). Wenn stattdessen die Variable
gleich 1432 ist, so wäre das Verhalten der Anweisung undefiniert,
weil 1432 mehr als drei Stellen hat. In diesem Fall wäre es notwendig
stattdessen ‘\4’ zu verwenden.

Falls die Variable negativ ist, so verwenden Sie stattdessen ‘\-3d’
(oder ‘\-4d’). LDmicro wird hierdurch veranlasst eine vorgestellte
Freistelle für positive Zahlen und ein vorgestelltes Minuszeichen für
negative Zahlen auszugeben.

Falls mehrere “Formatierte Zeichenfolge”-Anweisungen zugleich ausgegeben
werden (oder wenn eine neue Zeichenfolge ausgegeben wird bevor die
vorherige vollendet ist), oder auch wenn diese mit UART TX Anweisungen
vermischt, so ist das Verhalten undefiniert.

Es ist auch möglich diese Anweisung für eine feste Zeichenfolge zu
verwenden, die über den seriellen Anschluss gesendet wird, ohne den Wert
einer Ganzzahlvariablen in den Text zu interpolieren. In diesem Fall
fügen Sie einfach diese spezielle Steuerungsfolge nicht ein.

Verwenden Sie ‘\\’ für einen zeichengetreuen verkehrten Schrägstrich.
Zusätzlich zur Steuerungsfolge für die Interpolierung einer Ganzzahl-
Variablen, sind die folgenden Steuerungszeichen erhältlich:

        * \r   -- carriage return      Zeilenschaltung
        * \n   -- new line             Zeilenwechsel
        * \f   -- form feed            Formularvorschub
        * \b   -- backspace            Rücksetzen
        * \t   -- horizontal tab
        * \v   -- vertical tab
        * \a   -- alert
        * \xAB -- character with ASCII value 0xAB (hex)
               -- Schriftzeichen mit ASCII-Wert 0xAB (hex)

Der Ausgangszustand des Netzwerks dieser Anweisung ist ‘wahr’, während
diese Daten überträgt, ansonsten ‘unwahr’. Diese Anweisung benötigt eine
große Menge des Programmspeichers, insofern sollte sie sparsam verwendet
werden. Die gegenwärtige Umsetzung ist nicht besonders effizient, aber
eine bessere würde Änderungen an sämtlichen Ausläufern des Programms
benötigen.


> FORMATIERTE ZEICHENFOLGE                   dest
                                       -{"Zeichenkette", var}-

Für Zielplattformen (z.B. Netzer) auf denen bereits ein printf
verfügbar ist, kann dieser Befehl verwendet werden.

Wenn der Eingangszustand des Netzwerks für diese Anweisung von ‘unwahr’
auf ‘wahr’ übergeht, so beginnt diese die Zeichenfolge mittels printf
zu bearbeiten und gibt sie auf der Zielvariablen aus.

Die Zeichenkette wird vollständig in das Kompilat eingebettet. Es gelten
die Formatierungsregeln von printf.

Die Variable kann eine beliebige Variable aus dem Programmbereich
sein. Die printf Funktion der Zielplatform wird auf sie zugreifen,
sobald ein Platzhalter in der Zeichenkette gefunden wird (z.B. %d).

Dest ist ein Register, auf das das Ergebnis geschrieben wird. Das sollte
das obere Ende eines Ringpuffers oder FiFo-Speichers sein.
d des Netzwerks dieser Anweisung ist ‘wahr’,
Der Ausgangszustand des Netzwerks dieser Anweisung ist immer ‘wahr’,


EIN HINWEIS ZUR VERWENDUNG DER MATHEMATIK
=========================================

Denken Sie daran, dass LDmicro nur 16-Bit mathematische Operationen
ausführt. Dies bedeutet, dass das Endresultat jeder Berechnung,
die Sie vornehmen, eine Ganzzahl zwischen -32768 und 32767 sein muss.
Dies bedeutet auch, dass die Zwischenergebnisse Ihrer Berechnungen alle
in diesem Bereich liegen müssen.

Wollen wir zum Beispiel annehmen, dass Sie folgendes berechnen möchten
y = (1/x) * 1200, in der x zwischen 1 und 20 liegt.
Dann liegt y zwischen 1200 und 60, was in eine 16-Bit Ganzzahl passt,
so wäre es zumindest theoretisch möglich diese Berechnung auszuführen.
Es gibt zwei Möglichkeiten, wie Sie dies codieren könnten: Sie können
die Reziproke (Kehrwert) ausführen and dann multiplizieren:

   ||         {DIV  temp  :=}          ||
   ||---------{ 1 / x       }----------||
   ||                                  ||
   ||          {MUL  y  :=  }          ||
   ||----------{ temp * 1200}----------||
   ||                                  ||

Oder Sie könnten einfach die Division in einem Schritt direkt vornehmen.

   ||           {DIV  y  :=}           ||
   ||-----------{ 1200 / x }-----------||


Mathematisch sind die zwei äquivalent; aber wenn Sie diese ausprobieren,
so werden Sie herausfinden, dass die erste ein falsches Ergebnis von
y = 0 liefert. Dies geschieht, weil die Variable einen Unterlauf
[= resultatabhängige Kommaverschiebung] ergibt.  So sei zum Beispiel x = 3,
(1 / x) = 0.333, dies ist aber keine Ganzzahl; die Divisionsoperation
nähert dies, als 'temp = 0'. Dann ist y = temp * 1200 = 0. Im zweiten
Fall gibt es kein Zwischenergebnis, welches einen Unterlauf [= resultats-
abhängige Kommaverschiebung] ergibt, somit funktioniert dann alles.

Falls Sie Probleme bei Ihren mathematischen Operationen erkennen,
dann überprüfen Sie die Zwischenergebnisse auf Unterlauf [eine
resultatabhängige Kommaverschiebung] (oder auch auf Überlauf, der dann
im Programm in Umlauf kommt; wie zum Beispiel 32767 + 1 = -32768).
Wann immer möglich, wählen Sie Einheiten, deren Werte in einem Bereich
von -100 bis 100 liegen.

Falls Sie eine Variable um einen bestimmten Faktor vergrößern müssen, tun
Sie dies, indem Sie eine Multiplikation und eine Division verwenden. Um
zum Beispiel y = 1.8 * x zu vergrößern, berechnen Sie y = (9/5) * x,
(was dasselbe ist, weil 1,8 = 9/5 ist), und codieren Sie dies als
y = (9 * x)/5, indem Sie die Multiplikation zuerst ausführen.

   ||         {MUL  temp  :=}          ||
   ||---------{ x * 9       }----------||
   ||                                  ||
   ||           {DIV  y  :=}           ||
   ||-----------{ temp / 5 }-----------||


Dies funktioniert mit allen x < (32767 / 9), oder x < 3640.  Bei höheren
Werten würde die Variable ‘temp’ überfließen. Für x gibt es eine
ähnliche Untergrenze.


KODIER-STIL
===========

Ich gestatte mehrere Spulen in Parallelschaltung in einem einzigen
Netzwerk unterzubringen. Das bedeutet, sie können ein Netzwerk, wie
folgt schreiben:

   ||       Xa               Ya        ||
 1 ||-------] [--------------( )-------||
   ||                                  ||
   ||       Xb               Yb        ||
   ||-------] [------+-------( )-------||
   ||                |                 ||
   ||                |       Yc        ||
   ||                +-------( )-------||
   ||                                  ||

Anstatt diesem:

   ||       Xa               Ya        ||
 1 ||-------] [--------------( )-------||
   ||                                  ||
   ||                                  ||
   ||                                  ||
   ||                                  ||
   ||       Xb               Yb        ||
 2 ||-------] [--------------( )-------||
   ||                                  ||
   ||                                  ||
   ||                                  ||
   ||                                  ||
   ||       Xb               Yc        ||
 3 ||-------] [--------------( )-------||
   ||                                  ||

Rein theoretisch bedeutet das, dass Sie irgendein Programm, als ein
gigantisches Netzwerk, schreiben könnten. Und es bestünde überhaupt
keine Notwendigkeit mehrere Netzwerke zu verwenden. In der Praxis ist
dies aber eine schlechte Idee, denn wenn Netzwerke komplexer werden, so
werden sie auch schwieriger zu editieren, ohne Löschen und neu Schreiben
von Anweisungen.

Jedoch, ist es manchmal ein guter Einfall, verwandte Logik in einem
einzelnen Netzwerk zusammenzufassen. Dies erzeugt einen beinahe
identischen Code, als ob sie getrennte Netzwerke entworfen hätten, es
zeigt aber, dass diese Anweisungen (Logik) verwandt ist, wenn man diese
im Netzwerk-Diagramm betrachtet.

            *                *                *

Im Allgemeinen hält man es für eine schlechte Form, den Code in einer
solchen Weise zu schreiben, dass sein Ergebnis von einer Folge von
Netzwerken abhängt. So zum Beispiel ist der folgende Code nicht besonders
gut, falls ‘xa’ und ‘xb’ jemals ‘wahr’ würden.

   ||       Xa         {v  :=       }  ||
 1 ||-------] [--------{ 12      MOV}--||
   ||                                  ||
   ||       Xb         {v  :=       }  ||
   ||-------] [--------{ 23      MOV}--||
   ||                                  ||
   ||                                  ||
   ||                                  ||
   ||                                  ||
   ||      [v >]             Yc        ||
 2 ||------[ 15]-------------( )-------||
   ||                                  ||

Ich werde diese Regel brechen und indem ich dies so mache, entwerfe ich
einen Code-Abschnitt, der erheblich kompakter ist. Hier zum Beispiel,
zeige ich auf, wie ich eine 4-Bit binäre Größe von ‘xb3:0’ in eine
Ganzzahl wandeln würde.

   ||                                   {v  :=       }  ||
 3 ||-----------------------------------{ 0       MOV}--||
   ||                                                   ||
   ||       Xb0                  {ADD  v  :=}           ||
   ||-------] [------------------{ v + 1    }-----------||
   ||                                                   ||
   ||       Xb1                  {ADD  v  :=}           ||
   ||-------] [------------------{ v + 2    }-----------||
   ||                                                   ||
   ||       Xb2                  {ADD  v  :=}           ||
   ||-------] [------------------{ v + 4    }-----------||
   ||                                                   ||
   ||       Xb3                  {ADD  v  :=}           ||
   ||-------] [------------------{ v + 8    }-----------||
   ||                                                   ||

Falls die TRANSFER-Anweisung (MOV) an das untere Ende des Netzwerks
gebracht würde, anstatt auf das obere, so würde der Wert von ‘v’, an
anderer Stelle im Programm gelesen, gleich Null sein. Das Ergebnis dieses
Codes hängt daher von der Reihenfolge ab, in welcher die Anweisungen
ausgewertet werden.  Im Hinblick darauf, wie hinderlich es wäre, diesen
Code auf eine andere Weise zu schreiben, nehme ich dies so hin.


BUGS
====

LDmicro erzeugt keinen sehr effizienten Code; es ist langsam in der
Ausführung und geht verschwenderisch mit dem Flash- und RAM-Speicher
um. Trotzdem kann ein mittelgroßer PIC- oder AVR-Prozessor alles, was
eine kleine SPS kann, somit stört dies mich nicht besonders.

Die maximale Länge der Variabelen-Bezeichnungen (-Namen) ist sehr
begrenzt. Dies ist so, weil diese so gut in das KOP-Programm (ladder)
passen. Somit sehe ich keine gute Lösung für diese Angelegenheit.

Falls Ihr Programm zu groß für die Zeit-, Programmspeicher- oder
Datenspeicher-Beschränkungen des Prozessors ist, den Sie gewählt haben,
so erhalten Sie keine Fehlermeldung. Es wird einfach irgendwo anders alles
vermasseln. (Anmerkung: Das AVR STK500 gibt hierzu Fehlermeldungen aus.)

Unsorgfältiges Programmieren bei den Datei Öffnen/Abspeichern-Routinen
führen wahrscheinlich zu der Möglichkeit eines Absturzes oder es wird
ein willkürlicher Code erzeugt, der eine beschädigte oder bösartige .ld
Datei ergibt.

Bitte berichten Sie zusätzliche Bugs oder richten Sie Anfragen für neue
Programm-Bestandteile an den Autor (in Englisch).

Thanks to:
    * Marcelo Solano, for reporting a UI bug under Win98
    * Serge V. Polubarjev, for not only noticing that RA3:0 on the
      PIC16F628 didn't work but also telling me how to fix it
    * Maxim Ibragimov, for reporting and diagnosing major problems
      with the till-then-untested ATmega16 and ATmega162 targets
    * Bill Kishonti, for reporting that the simulator crashed when the
      ladder logic program divided by zero
    * Mohamed Tayae, for reporting that persistent variables were broken
      on the PIC16F628
    * David Rothwell, for reporting several user interface bugs and a
      problem with the "Export as Text" function

Particular thanks to Heinz Ullrich Noell, for this translation (of both
the manual and the program's user interface) into German.


COPYING, AND DISCLAIMER
=======================

DO NOT USE CODE GENERATED BY LDMICRO IN APPLICATIONS WHERE SOFTWARE
FAILURE COULD RESULT IN DANGER TO HUMAN LIFE OR DAMAGE TO PROPERTY. THE
AUTHOR ASSUMES NO LIABILITY FOR ANY DAMAGES RESULTING FROM THE OPERATION
OF LDMICRO OR CODE GENERATED BY LDMICRO.

This program is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation, either version 3 of the License, or (at your
option) any later version.

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>.


Jonathan Westhues

Rijswijk      -- Dec 2004
Waterloo ON   -- Jun, Jul 2005
Cambridge MA  -- Sep, Dec 2005
                 Feb, Mar 2006

Email: user jwesthues, at host cq.cx


