Bibliothek erstellen - Grundlagen
Die externen Bibliotheken werden durch einen dafür extra vorhandenen, mächtigen Bibliotheks-Editor bearbeitet und/oder erstellt. Der Bibliotheks-Editor unterstützt den Autor einer Bibliothek grafisch durch Übersichten und leicht verständlichen Auswahlmöglichkeiten beim Erstellen von Methoden und Eigenschaften.
Die eigentlichen Bibliotheksfunktionen werden klassisch in Assembler programmiert.
In den Quelltexten der Interfaces und Module können Funktionen und Makros der Standardbibliothek verwendet werden. Mit .import <label> kann ein externes Label importiert werden. Auch ist die Verwendung von Funktionen anderer Bibliotheken möglich. Durch die Verwendung der Präprozessorfunktion Defined() kann abgefragt werden, ob der Luna-Programmierer auch die notwendige Bibliothek eingebunden hat.
UM NAMENKOLLISIONEN ZU VERMEIDEN, MÜSSEN SÄMTLICHE BEZEICHNER VON DEFINES, KONSTANTEN, LABELS UND MAKROS INNERHALB EINER BIBLIOTHEK EINMALIG UND EINDEUTIG SEIN.
Es können sämtliche allgemeinen Präprozessorfunktionen des Luna-Assemblers genutzt werden wie in Inline-Assembler möglich, wie z.B. hi8(), lo8(), Schiebebefehle usw. Zusätzlich stehen spezielle Präprozessor-Befehle bereit, die nur bei der Erstellung von Bibliotheken Sinn machen (siehe unten).
Siehe auch:
Calls
Aufrufe/Sprünge von/zu Bibliotheksinternen oder externen Methoden/Subroutinen sollte immer mit dem Befehl call bzw. jmp erfolgen, außer das Ziel befindet sich innerhalb der eigenen Methode/Subroutine. Der Optimierer des Assemblers optimiert hier automatisch zu den effizienteren indirekten Varianten rcall und rjmp. Auf Controllern die diese direkten Sprünge nicht unterstützen, werden call und jmp automatisch durch rcall und rjmp ersetzt.
Spezielle Präprozessorfunktion(en)
.regisr
Diese besondere Direktive erlaubt das Registrieren eines Labels auf einen anzugebenden Interrupt-Vektor.
Syntax
- .regisr vectorAddr, label
;register the interrupt service routine to the timer-overflow-interrupt ;an error occours by the assembler, when the isr is already defined .regisr OVF0addr,__myIsr
MakeIdentifier( string )
Erstellt aus der übergebenen Zeichenkette einen Bezeichner (Symbol). Die Zeichenkette wird anschließend vom Assembler nicht mehr als Zeichenkette betrachtet, sondern als Konstantenname (Symbol). Wurde dieser Konstantenname bereits mit einem Wert belegt, kann er anschließend auch als Solcher im Assembler-Quelltext verwendet werden.
Beispiel
Zuweisung 0xf0 auf das bereits vorhande Register-Symbol PORTB. Die Konstante myport verweist dann auf die Konstante (Symbol) PORTB, sodass im Ergebnis hier der Wert von PORTB verwendet wird.
.set myport = MakeIdentifier("PORTB") ldi _HA0,0xf0 sts myport,_HA0
Mit folgendem Code lässt sich beispielsweise in einem Interface ein bestimmter, im Luna-Code zugewiesener Port-Pin im Assemblerquelltext verwenden.
Luna-Code
Spi.PinMiso = PortB.2
Interface Inline-Methode "PinMiso"
.set SpiPinMisoPORT = MakeIdentifier(NthField({keyword},".",1)) .set SpiPinMisoPortPin = val(NthField({keyword},".",2)) .set SpiPinMisoDDR = MakeIdentifier("DDR"+right(NthField({keyword},".",1),1)) .set SpiPinMisoPIN = MakeIdentifier("PIN"+right(NthField({keyword},".",1),1))
Im Library-Editor
Bei solchen Zuweisungen ist das ein wenig wie Textverarbeitung. Es wird die Eingabe des Programmierers so aufbereitet, dass man auf der Assemblerebene mit den Informationen sinnvoll arbeiten kann. Die Deklaration dieser Inline-Methode wiederum stellt sicher, dass der Programmierer ohne eine Fehlermeldung zu erhalten nur das eingeben kann, was er eingeben können soll. Dies wird hier durch den regulären Ausdruck sichergestellt.
In diesem Beispiel enthalten die vier Konstanten anschließend folgende Werte:
- SpiPinMisoPORT = PORTB
- SpiPinMisoPortPin = 2
- SpiPinMisoDDR = DDRB
- SpiPinMisoPIN = PINB