Ich kann hier keinen kompletten Einführungskurs geben. Das folgende sollte reichen, um dir eine Vorstellung zu geben, wie man etwas, daß man in C formulieren kann, auf der SPS formuliert.
Ansonsten würde ich dir raten, dein Problem zunächst in C oder VB (nicht C++) zu programmieren. Du kannst dabei Regler und Regelstrecke leicht simulieren und per Tastendruck "Störungen" oder Sollwertsprünge simulieren.
Nachher kannst du die Teile posten, von denen du nicht weißt, wie du sie auf der SPS umsetzen sollst.
Assembler ist gut. Dann stell dir die S7 als eine Akkumulator-orientierte CPU vor (wie ein 6502).
Um etwas aus dem Speicher zu bekommen, mußt du es in den Akku laden:
L MW0
Den Akku kannst du wieder in den Speicher schreiben:
T MW2
Speicher kannst du als Bytes, Worte und Doppelworte ansprechen.
Speicher gibt's als einen zusammenhängenden Bereich M und als viele Datenbausteine. Datenbausteine brauchen immer die Datenbausteinnummer, so ein bischen wie die Segmentregister des 8086. Allerdings muß man sie erst anlegen, ein bischen wie malloc oder getmem, aber eher wie die Memory Descriptors beim 80386. Angelegt werden sie am besten in passender Größe mit Step7
Angesprochen werden sie dann:
L DB1
W0 //lädt das erste Datenwort aus DB1
L DB1
W6 //lädt das 7. Datenwort aus DB1
L DB10
W0 //lädt das erste Datenwort aus DB10
Oder
AUF DB10
//
// ab jetzt geht alles mit DB10
//
L DW0 //lädt das erste Datenwort aus DB10
L DW6 //lädt das 7. Datenwort aus DB10
Die Notation mit AUF ist kürzer und schneller, denn bei
L DB10
W0 //lädt das erste Datenwort aus DB10
erzeugt Step7 die Befelsfolge:
AUF DB10
L DW0
Du kannst mit indizierter Adressierung arbeiten:
L MW[MD0] // lade das Merkerwort, dessen Adresse in Merker-Doppelwort MD0 steht.
Die Adresse ist gleich der Anzahl BITS, die du zu 0 dazuzählen müsstest
Wenn MD0 hier 64 ist, wird das MW8 geladen.
Das geht auch für DWs
L DW[MD0] // lade das Datenwort, dessen Adresse in Merker-Doppelwort MD0 steht.
Nicht geht:
L DB10
W[MD0] // FALSCH!!
sondern:
AUF DB10
L DW[MD0]
Beim Rechnen wird
1. Etwas in den Akku geladen. Dabei wird immer der Inhalt vonAKKU1 nach AKKU2 geladen.
2. Etwas in den Akku geladen. Dabei wird immer der Inhalt vonAKKU1 nach AKKU2 geladen.
3. Eine Rechenoperation mit AKKU1 und 2 ausgeführt. Ergebnis in AKKU1.
Wenn also AKKU1 ein Ergebnis enthält, mit dem weitergerechnet werden soll, kannst du dir das 1.Laden sparen.
Ergebnisse können getestet und in Abhängigkeit davon bedingte Sprünge ausgeführt werden:
<=R // vergleicht die 32-Bit-Inhalte der Akkus, ob sie als Gleitpunkt (float) Zahlen kleiner gleich sind. Welcher mit welchem verglichen wird vergeß ich immer...
SPB MARKe // springt zu einer Marke, Marken haben bis zu 4 Zeichen
L MD 44 // dieser Befehl wird dann übersprungen
MARK: NOP 0 // An einer Marke muß immer auch eine Anweisung stehen. Nackte Marken (Labels) gibt`s nicht. Das NOP empfiehlt sich dafür, weil man nachherdie Programmstruktur leichter ändern kann.
Mit Rückwärtssprüngen kann man Schleifen bauen.
Das ist aber nicht unbedingt gesund und üblich, denn:
1. Wird die Ausführungszeit überwacht. Ein Steuerungsprogramm, daß auf äußere Ereignisse reagieren muß, darf nicht mal eben einen Endschalter überfahren, weil es in einer langen Schleife herumrechnet.
2. Sind Schleifen oft nicht nötig, da der OB1 eh in einer Endlosschleife ausgeführt wird. In dem man pro OB1-Durchlauf das tut, was ein Schleifendurchlauf täte, kann man viele Schleifen-Konstrukte ersetzen.