Pointer (sPtr, dPtr, ePtr)
Pointer sind spezielle intrinsische Variablen. Intrinsisch bedeutet, dass der Wert den sie speichern als eine Adresse auf einen Speicherbereich interpretiert wird. Stringvariablen und MemoryBlocks sind ebenfalls intrinsische Variablen.
Pointern kommt jedoch eine besondere Bedeutung zu: Sie können wie Word-Variablen mit Werten belegt werden und man kann mit ihnen Rechnungen durchführen. Weiterhin sind die Objektfunktionen des MemoryBlocks darauf anwendbar, also beispielsweise p.ByteValue(0) = 0x77 usw.
Da der Controller über drei unterschiedliche Speichersegmente verfügt, wurden auch drei verschiedene Pointer-Typen als neuer Datentyp implementiert. Dies sind:
- sptr: Pointer auf Adressen im Arbeitsspeicher (sram segment)
- dptr: Pointer auf Adressen im Flash (data segment)
- eptr: Pointer auf Adressen im Eeprom (eeprom segment)
Mit Pointern ist es also möglich, auf eine beliebige Adresse, z.Bsp. innerhalb eines MemoryBlocks oder in einer Flash-Tabelle mit den Objektfunktionen zuzugreifen:
Beispiel im Datensegment (Direktzugriff):
dim pd as dptr pd = table.Addr print "pd = 0x";hex(pd);" ";34;pd.StringValue(2,12);34 do loop data table .dw myfunc1 .db "Menu Nr. 1 " .dw myfunc2 .db "Menu Nr. 2 " .dw myfunc3 .db "Menu Nr. 3 " enddata
Das Ganze ist vergleichbar mit den Zugriffen über das Sram, Flash oder Eeprom-Interface, bei denen man im Unterschied zu den Pointern absolute Adressangaben vornehmen muss (also nicht zwangsläufig etwas super neues). Bei Pointern ist aber eine weitere Besonderheit vorhanden: Die Möglichkeit zum SuperImposing mit Strukturen.
SuperImpose
SuperImposing ist das „darüberlegen“ einer Strukturdeklaration auf einen beliebigen Speicherbereich. D.h. wenn man bspw. eine Struktur in Form eines Menüelements deklariert hat, lässt sich mit Pointern diese Strukturdeklaration auf den Speicherbereich abbilden/maskieren und kann dann die Elemente der Struktur elegant lesen. Das SuperImposing/Maskieren von Strukturdeklarationen auf Speicherbereiche ist auf die Verwendung mit Pointern beschränkt.
Syntax
Die Syntax ist denkbar einfach, wobei jedoch bestimmte Vorgaben einzuhalten sind. Bei einer Strukturdeklaration handelt es sich um eine virtuelle Definition, welche dem Compiler mitteilt wie der Zugriff erfolgen soll:
mypointer.<StrukturName>[( Index )].<StrukturElement>
Ist das Strukturelement eine weitere Struktur, verschachtelt sich der Aufruf entsprechend tiefer.
Index ist ein optionaler Konstantenwert bzw. ab Version 2013.r5 ein Ausdruck (z.B. Variable), der den Startoffset auf Basis der Gesamten Strukturgröße ergibt. D.h. ist die Struktur mitsamt seiner Elemente 4 Bytes groß, würde Index = 2 zu einer Startadresse + 8 führen, ab der die Struktur über den Speicherbereich gelegt wird.
Anwendung
Strukturdeklaration:
struct ENTRY word fnAddr string text[12] endstruct
Pointer für Flash-Segment dimensionieren:
dim pd as dptr
Pointer mit Adresse der Tabelle belegen:
pd = table.Addr
Indirekter Zugriff über Strukturdeklaration, die ab der im Pointer abgelegten Adresse über den Speicherbereich gelegt wird (superimpose). Bei Angabe eines Arrayindex bei einer Struktur, wird der Offset automatisch berechnet:
print "fnAddr = 0x";hex(pd.ENTRY(0).fnAddr);", menu text = ";34;pd.ENTRY(0).text;34 print "fnAddr = 0x";hex(pd.ENTRY(1).fnAddr);", menu text = ";34;pd.ENTRY(1).text;34 print "fnAddr = 0x";hex(pd.ENTRY(2).fnAddr);", menu text = ";34;pd.ENTRY(2).text;34
Die Tabelle im Flash:
data table .dw myfunc1 .db "Menu Nr. 1 " .dw myfunc2 .db "Menu Nr. 2 " .dw myfunc3 .db "Menu Nr. 3 " enddata
Beispielprogramm
- pointer.luna
const F_CPU=20000000 avr.device = atmega328p avr.clock = F_CPU avr.stack = 64 uart.baud = 19200 uart.recv.enable uart.send.enable struct ENTRY word fnAddr string text[12] endstruct dim a as byte dim ps as sptr dim pd as dptr dim m as MemoryBlock print 12;"pointer and superimpose example" print m.New(64) m.WordValue(0) = 0xaabb m.CString(2) = "Entry Nr. 1 " m.WordValue(14) = 0xccdd m.CString(16) = "Entry Nr. 2 " m.WordValue(28) = 0xeeff m.CString(30) = "Entry Nr. 3 " ps = m.Ptr 'Speicheradresse der MemoryBlock-Daten pd = table.Addr 'Speicheradresse der Tabelle im Flash 'direkt über Objektfunktionen print "(sram) ";34;ps.StringValue(2,12);34 print "(flash) ";34;pd.StringValue(2,12);34 print 'SuperImpose ' 'SuperImposing ist das "darüberlegen" einer Strukturdeklaration auf einen beliebigen Speicherbereich. 'D.h. wenn man bspw. eine Struktur in Form eines Menüelements deklariert hat, lässt sich mit Pointern 'diese Strukturdeklaration auf den Speicherbereich abbilden und kann dann die Elemente der 'Struktur elegant lesen. Bei Angabe eines Arrayindex (Konstante) bei einer Struktur, wird der 'Offset automatisch berechnet. print "sram:" print "fnAddr = 0x";hex(ps.ENTRY(0).fnAddr);", menu text = ";34;ps.ENTRY(0).text;34 print "fnAddr = 0x";hex(ps.ENTRY(1).fnAddr);", menu text = ";34;ps.ENTRY(1).text;34 print "fnAddr = 0x";hex(ps.ENTRY(2).fnAddr);", menu text = ";34;ps.ENTRY(2).text;34 print print "flash:" print "fnAddr = 0x";hex(pd.ENTRY(0).fnAddr);", menu text = ";34;pd.ENTRY(0).text;34 print "fnAddr = 0x";hex(pd.ENTRY(1).fnAddr);", menu text = ";34;pd.ENTRY(1).text;34 print "fnAddr = 0x";hex(pd.ENTRY(2).fnAddr);", menu text = ";34;pd.ENTRY(2).text;34 print print "Aufruf per Icall aus der Tabelle:" icall pd.ENTRY(0).fnAddr icall pd.ENTRY(1).fnAddr icall pd.ENTRY(2).fnAddr print print "ready" do loop procedure myfunc1() print "myfunc 1" endproc procedure myfunc2() print "myfunc 2" endproc procedure myfunc3() print "myfunc 3" endproc 'Wichtiger Hinweis: 'Adressen von Labels, Objekten oder Methoden liegen im Flash immer an einer Word-Grenze, sie werden 'im Flash-Objekt daher auch als Word-basierte Adresse abgelegt. Möchte man mit der Byte-Adresse arbeiten, 'muss man den Wert wie im Assembler mit 2 multiplizieren. data table ENTRY { myfunc1, "Menu Nr. 1" } ENTRY { myfunc2, "Menu Nr. 2" } ENTRY { myfunc3, "Menu Nr. 3" } enddata