Ladder Logic für PIC's und AVR's

(translated from the English original; thanks to Heinz Ullrich Noell)

Kurze Zusammenfassung: Ich habe einen Compiler geschrieben, mit einem Kontaktplan-Programm (ladder diagram) und der einen systemspezifischen PIC16 oder AVR-Code erzeugt. Die Anweisungen (Features) enthalten:

Sie können es download it for free. Oder mit mehr Hintergrund:

Einführung

Eine SPS wird oftmals in Kontaktplan (ladder logic) programmiert. Dies ist so, weil die SPS ursprünglich relaisgesteuerte Systeme ersetzte, und vierzig Jahre später sind wir immer noch nicht ganz davon abgekommen. Eine SPS, so wie jeder andere Mikroprozessor auch, arbeitet eine Anweisungsliste in Aufeinanderfolge ab. Kontaktplan-Anweisungen abstrahieren dies; man kann die SPS programmieren, indem man die Relaiskontakte und Spulen auf dem Bildschirm verdrahtet. Die SPS-Laufzeit wird den diesen von Ihnen gezeichneten Stromkreis nachvollziehen (simulieren). Einige der Kontakte können auf Eingänge von Außen festgelegt werden; einige Spulen auf Ausgänge. Auf diese Weise können Sie Ihren 'simulierten Schaltkreis’ mit anderen Geräten sich gegenseitig beeinflussen lassen und tatsächlich steuern. Das ist der eigentliche Punkt.

Tatsächlich geht dies aber weiter, weil Sie auch Timer, Zähler und aritmetische Operationen mit einfließen lassen können, was mit Relais nicht ganz einfach auszuführen wäre. Das Konzept eines Schaltkreises ist aber doch hilfreich, teilweise weil es gefühlsmäßig intuitiv ist, aber auch weil es gleichzeitige Sachverhalte abstrahiert. Das sieht, wie folgt aus:

         ||       Xa               Xb              Yout       ||
       1 ||-------] [------+-------] [------+-------( )-------||
         ||                |                |                 ||
         ||                |       Xc       |                 ||
         ||                +-------]/[------+                 ||

Dies ist ein einfacher Teil einer Schaltungslogik. Es gibt drei Eingangsbedingungen, Xa, Xb, und Xc. Und es gibt eine Ausgangsbedingung, Yout. Der Ausdruck ist, Yout := Xa und (Xb odr (nicht Xc)). Dies macht Sinn, wenn Sie Xa and Xb für Schließer halten, Xc für einen Öffner und Yout für eine Spule. Natürlich wird dies noch komplizierter:

         ||                                                   ||
         ||                                      Asetpoint    ||
       1 ||-------------------------------------{READ ADC}----||
         ||                                                   ||
         ||                                    Atemperature   ||
         ||-------------------------------------{READ ADC}----||
         ||                                                   ||
         ||                                                   ||
         ||                                                   ||
         ||                                                   ||
         ||                        {SUB  min_temp  :=}        ||
       2 ||------------------------{ Asetpoint - 20  }--------||
         ||                                                   ||
         ||                        {ADD  max_temp  :=}        ||
         ||------------------------{ Asetpoint + 20  }--------||
         ||                                                   ||
         ||                                                   ||
         ||                                                   ||
         ||                                                   ||
         ||[Atemperature >]                       Yheater     ||
       3 ||[ max_temp     ]+------------------------(R)-------||
         ||                |                                  ||
         ||     Xenable    |                                  ||
         ||-------]/[------+                                  ||
         ||                                                   ||
         ||[Atemperature <]      Xenable          Yheater     ||
         ||[ min_temp     ]--------] [--------------(S)-------||
         ||                                                   ||
         ||                                                   ||
         ||                                                   ||
         ||                                                   ||
         ||                       {SUB  check_temp  :=}       ||
       4 ||-----------------------{ Asetpoint - 30    }-------||
         ||                                                   ||
         ||                                                   ||
         ||                                                   ||
         ||                                                   ||
         ||[Atemperature >]                       Yis_hot     ||
       5 ||[ check_temp   ]-------------------------( )-------||
         ||                                                   ||
         ||                                                   ||
         ||                                                   ||
         ||------[END]----------------------------------------||
         ||                                                   ||
         ||                                                   ||

Dieses Beispiel steht für ein einfaches Thermostat. Es gibt zwei analoge Eingänge, davon einer für den Sollwert, welcher mit einem Topf verbunden sei, und der Anwender stellt die erwünschte Temperatur ein. Der andere ist für die Temperaturmessung vorgesehen; es könnte ein Halbleiter Temperatur-Fühler sein oder ein Pt100-Fühler mit einem passenden gekoppelten Schaltkreis. Der digitale Ausgang Yheater, der das Heizelement mittels eines passenden Schalters steuert (ein TRIAC, ein Relais, ein Halbleiterrelais oder welches auch immer).

Wir schließen die Schleife mit einem simplen Hysterese-Regler (bang-bang). Wir haben plus oder minus 20 Einheiten des Analog-Digital-Wandlers gewählt. Dies bedeutet, wenn die Temperatur unter den Sollwert (-20) fällt, so schalten wir die Heizung ein und wenn sie über den Sollwert (+20) steigt, stellen wir die Heizung ab.

Ich entschloß mich das Ganze noch ein wenig mehr aufzuputzen. Zunächst gibt es da noch einen Freigabe-Eingang: Die Heizung wird zwangsabgeschaltet, wenn der Eingang Xenable 'low’ ist. Auch fügte ich eine Anzeigelampe ein = Yis_hot, um anzuzeigen, ob die Temperatur sich innerhalb der Regelung befindet. Diese vergleicht gegen einen Schwellwert, der leicht kälter ist, als der Sollwert (-20), sodass die Lampe nicht im periodischen Durchlauf des Thermostats flackert.

Dies ist ein schlichtes Beispiel, aber es sollte klar werden, dass diese Programmiersprache recht ausdrucksstark ist. KOP (ladder logic) ist keine Universal-Programmiersprache, aber sie ist "Turing-complete" (Turing = Ein Mathematiker; Turing-complete = fähig nachzubilden oder zu emulieren), in der Industrie akzeptiert, und für eine begrenzte Klasse von Problemen (meistens regelungs-orientiert) erstaunlich zweckdienlich.

Ein KOP-Compiler für PIC16 und AVR

Moderne unter drei US-Dollar kostende Mikroprozessoren haben wahrscheinlich die gleiche Rechenleistung, wie eine SPS von 1975. Daher sehen sie mehr als genug MIPS (Recheneinheit für Computerleistung) vor, um ein einigermaßen komplexes KOP-Programm mit einer Zykluszeit von ein paar Millisekunden laufen zu lassen. Ich denke, dass eine SPS für gewöhnlich ein Art Laufzeit hat, die in etwa den Interpretern von virtuellen Maschinen ähnlich sind, aber wenn wir es mit einfacher Prozessor-Logik, ohne viel Speicher, zu tun haben, dann dürfte ein Compiler die bessere Lösung sein.

So schrieb ich einen Compiler. Sie beginnen mit einem leeren Netzwerk. Sie können Kontakte hinzufügen (Eingänge) und Spulen (Ausgänge) und auch kompliziertere Strukturen, um Ihr Programm zu bilden. Timer (TON, TOF, RTO) werden unterstützt. Die max./min. Dauer hängen von der Zykluszeit der 'SPS’ ab, welche konfigurierbar ist; Timer können von Millisekunden bis zu dem Zehnfachen von Minuten zählen. Es gibt Zähler und arithmetische Operationen (plus, minus, mal, geteilt durch).

Steuerkreis Elemente können parallel oder in Reihe zu den schon existierenden Elemeneten hinzugefügt werden. Es wird eine E/A-Liste von dem KOP-Programm aufgebaut. Sie können interne Relais bilden (Rfoo), für welche ein Speicherplatz automatisch zugewiesen wird, oder Eingänge (Xfoo) und Ausgänge (Yfoo), denen Sie einen Pin des Mikroprozessors zuordnen müssen. Die Auswahl der verfügbaren Pins, hängt von dem gewählten Mikropozessor ab. Ich habe versucht, die populärsten PICs und AVRs zu unterstützen (siehe unten).

Sie können Ihr Programm in grafischer Form editieren:

Dann können Sie Ihr Programm in Echzeit testen. Das Programm erscheint auf dem Bilschirm mit den Kontakten (bzw. Anweisungen, arithmetisch oder vergleichend) hellrot leuchtend, die den Signalfluss in den Netzwerkzweigen passieren lassen. Dieserleichtert die Fehlersuche (debugging). Der Status der Variablen wird in der E/A-Liste unten auf der Maske angezeigt.

Wenn das Programm im Simulationsbetrieb funktioniert, können Sie den Ein- und Ausgängen Pins zuweisen und danach den AVR- oder PIC-Code erzeugen. Der Code-Generator ist nicht besonders schwer. Wenn Sie feststellen, dass eine parallele Verzweigung eine ODER-Glied ist und ein serielles ein UND-Glied ist, ist es eine Aufgabe für das zweite Studienjahr und nicht mal besonders lang. Der Editor ist eigentlich die grosse Herausforderung. Es würde einige Arbeit erfordern einen klugen Compiler zu entwickeln, jedoch ein guter Register-Verteiler für die AVR's, würde eine größere Beschleunigung dieser vorsehen. Wenn Sie sehr einfallsreich werden möchten, so könnten Sie Standard Logik-Reduktions-Algorithmen verwenden und vielleicht auch Status-Reduktionen. Das wäre erheblich schwerer. Die Timer vermasseln aber dann alles sowieso.

Auch wenn man dies alles übergeht, ist mein AVR Code-Generator sehr schwach. Der AVR-Nachrechner erzeugt noch PIC-Code... zum Beispiel nutzt er nicht wirklich den Vorteil der Tatsache, dass der AVR mehr als ein Register hat. Teilweise ist der erzeugte Code peinlich schlecht. Der PIC-Nachrechner ist besser, aber nicht wirklich großartig. Keiner von diesen Nachteilen ist aber von besonderer Bedeutung, bis Sie versuchen Dutzende von Netzwerken in einer sehr schnellen Zykluszeit laufen zu lassen.

Ich unterstütze A/D-Wandler, eine PWM-Einheit, und UART auf den Prozessoren, die diesen vorsehen. Dies bedeutet, dass Sie ein KOP-Programm schreiben können, welches analoge Eingänge einlesen kann, und über eine serielle Schnittstelle Zeichen sendet und empfängt  (z.B. zu einem PC, falls wenn Sie einen passenden Pegelumsetzer, wie den MAX232 einsetzen, oder auch zu einem Zeichen-LCD). Es ist sowohl möglich willkürliche Zeichenfolgen über die serielle Schnittstelle zu senden, als auch Werte von Ganzzahl-Variablen als ASCII-Text. Schließlich unterstütze ich jetzt auch 'zu erhaltende Variablen’ auf Prozessoren mit einem EEPROM. Sie können anweisen, dass eine bestimmte Variable automatisch, bei jeder Wertänderung, gespeichert wird, sodass ihr Wert bei Versorgungsspannungs-Abschaltungen erhalten bleibt.

Einschränkungen und Haftungsausschluß

Natürlich kann ein Mikroprozessor nicht alles, was eine SPS kann. Die meisten SPS-Umgebungen bieten mehr Anweisungen und vordefinierte Blöcke, als mein Programm. Die SPS-Hardware ist auch besser; normalerweise sind die Ein- und Ausgänge entwickelt, einen unglaublichen elektrischen Missbrauch ertragen zu können. Einen PIC16F877 auf einer Trägerplatte können Sie für 10-20 US-Dollar erwerben, jedoch für eine SPS mit den gleichen Möglichkeiten werden Sie ein nettes Sümmchen mehr bezahlen.

Bisher habe ich nur sehr wenige Fehler-Berichte (bug-reports) erhalten, im Vergleich zu der Anzahl von Leuten mit Fragen oder Bitten und weitere Anweisungen. Es besteht aber immer noch eine hohe Möglichkeit für Ausfälle, speziell bei den Mikroprozessoren, die ich nicht besitze und daher auch nicht testen kann. Gewiss sollte man LDmicro nicht für sicherheits-kritische Anwendungen verwenden, oder mit denen Sie ein teures Gerät zerstören könnten, wenn LDmicro ausfallen sollte.

Wie ich weiter oben schon anführte, ist der erzeugte Code noch weit entfernt vom Optimum. Auch steht nicht das gesamte Daten RAM für die PIC16-Prozessoren für die Kontaktplan-Programmierung zur Verfügung. Dies ist so, weil ich nicht den gesamten unsinnigen seitenorientierten Speicher unterstütze. Allerdings, unterstütze ich das Speicherorientierungs-Programm, welches notwendig ist, um Zugang zu den Speicherstellen über 2k zu erhalten.

Download

Diese Software ist unter Windows XP getestet. Unbestätigten Berichten zu Folge funktioniert sie auch unter Windows 98. Der Download ist ein .exe.file; es werden keine weiteren Dateien benötigt, somit gibt es kein Installationsprogramm. Speichern Sie es einfach irgendwo auf Ihrem Computer ab, lassen Sie es laufen und es wird funktionieren. Das zugehörige Handbuch ist in dem .exe file enthalten, Sie können es aber auch separat herunterladen, falls Sie dies wünschen.

Der Compiler erzeugt Intel IHEX-files. Die meisten Programmier-Softwares, die ich bisher gesehen habe, erwarten dies. Natürlich benötigen Sie eine Art von Programmiergerät, um diese 'hex-files’ in Ihre Chips zu bekommen. Für die AVR's empfehle ich einen STK300-artigen parallelen 'port dongle’, wie dieser von Olimex verkauft wird. Für die PIC's empfehle ich den PICkit2 von Microchip, welcher in deren web store erhältlich ist.

Ich schätze und anerkenne alle 'bug reports’ (Fehlerberichte). Die folgenden Chips werden unterstützt und sind getestet:

Die folgenden Chips werden unterstützt, sind aber nicht getestet. Sie sollten funktionieren, aber ohne Garantie. Falls Sie einen ausprobieren und er funktioniert, so würde ich mich über Ihre Erfolgsmitteilung freuen:

Es ist auch möglich einen C-Code des KOP-Programms zu erzeugen. Das ist zwar unbequemer, aber Sie können diesen dann für jeden Prozessor verwenden, für den Sie einen C-Compiler besitzen.

LDmicro kann auch einen interpretierbaren Byte-Code erzeugen. Falls Sie einen Interpreter schreiben wollen, dann können Sie Ihren KOP(ladder)-Code auf jedwedem Ziel verwenden. Es gibt nicht viel Dokumentation hierüber, aber ich habe einen Beispiels-Interpreter in gut übertragbarem 'C’ vorgesehen.

Hier das Programm:

Dieses Programm ist auch auf Deutsch erhältlich. Mit Dank an Heinz Ullrich Noell für diese Übersetzung, von beidem, dem Handbuch und der Programm-Bedieneroberfläche. Er kann unter der folgenden e-mail-Adresse erreicht werden: hunoell bei mastercabo.com.br

(rechts klicken, um eine dieser Dateien zu speichern)

Bitte berichten Sie alle Defekte. Dies ist Freeware mit keiner Abteilung, die mit einer Qualitätskontrolle betraut ist. Ich besitze noch nicht mal die Hardware, um viele Anwendungsziele selbst zu testen. Ein Fehler, der nicht berichtet wird, wird wahrscheinlich nie behoben.

Ich habe auch ein tutorial, in welchem ich beschreibe, wie man ein einfaches Kontaktplan(ladder)-Programm eingibt, es simuliert, ein IHEX-file generiert und dieses dann in den PIC-Prozessor programmiert. Dies ist wahrscheinlich die einfachste Art einen Einstieg in diese Software zu finden.

Der Quellcode von LDmicro ist nicht allgemein erhältlich. Falls Sie einen Zugang zu diesem Quellcode wünschen oder wenn Sie an einer maßgeschneiderten Version von LDmicro interessiert sind, dann nehmen Sie bitte für Ihre Anforderung Kontakt mit mir auf contact me.