Forum: Mikrocontroller und Digitale Elektronik .dw Tabelle einlesen, Lookup-Tabelle Assembler


von Daniel B. (daniel10)


Lesenswert?

Hallo liebes Forum :-)

Ich muss euch mal wieder belästigen, da ich zu diesem Thema nichts 
gefunden habe und mir fast so scheint, als ob das was ich vorhabe, 
garnicht geht.
Aber von meinen jetzigen Überlegungen heraus, müsste das gehen.

Und zwar ich baue ja an einem UV-Belichtungsscanner.
Ja, ich weiß, ist hier nicht so beliebt und UV-Röhren werden bevorzugt.
Aber das ist nicht das Thema ;-)

Ich möchte den Schrittmotor per 16-Bit Timer im CTC Interrupt-Modus 
ansteuern, das wie und wo ist schon geklärt, da es da eine schöne 
Application-Note von Atmel gibt.

Ich habe mir ein Menü mit Sprungtabellen aufgebaut, was auch 
funktiniert.
In den einzelnen Untermenüs kann ich Einstellungen vornehmen. Nun geht 
es darum, dem Microprozessor verständliche Werte in den Timer zu laden, 
um eine eingestellte Geschwindigkeit des Motors zu erhalten.
Angedacht sind jetzt 2 Tabellen, einmal eine Tabelle, die mir die Werte 
auf dem Display anzeigt und eine die die Zählstände für den Timer 
einhält.
Im Eeprom wird dann nur noch eine Tabellenzahl abgelegt.
z.b.: Anzeige auf Display: 150cm/min, entspricht Tabellen-Wert 2.
Gleichzeitig stellt der Wert 2 meine Tabellenzahl für den Zählstand des 
Timers in einer anderen Tabelle dar. Da das nur 10 sein werden, auch 
nicht allzu groß.

Nun muss ich eine 16-Bit Zahl aus der Tabelle lesen...

In der Tabelle müssten die Werte mit .dw beginnen, da ja 16-Bit
Also zb. .dw 960 für den Wert 960

ldi ZH,HIGH (2*Tabelle)
ldi ZL,LOW (2*Tabelle)
add ZL,Wert

lpm Temp0,Z

Soweit wäre die Theorie und Praxis für einen 8-Bit Wert.
Wie klappt das mit 16-Bit? Klappt das überhaupt?

evtl. so?
lpm Temp0,Z,LOW
lpm Temp1,Z,HIGH

Oder so?

lpm Temp0,Z
inc ZL
lpm Temp1,Z

Dann stehen die High-Bytes in Temp0, die Low-Bytes in Temp1?
Nur lese ich dann nicht die Nächste Adresse ein, wenn ich ZL erhöhe?

Hmm... vllt hat das schonmal jemand gemacht und könnte einem das mal 
zeigen, wie es funktionieren kann :-)

Alternativ käme mir noch die Idee, den gespeicherten Wert für eine 
Sprungtabelle zu nutzen.
In jedem Sprungziel werden dann die jeweiligen Zahlen in den Timer 
geladen.
Nur sind das dann ja wieder 10 Sprungziele, hmm...

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Daniel B. schrieb:
> Oder so?
>
> lpm Temp0,Z
> inc ZL
> lpm Temp1,Z

 So:
1
  lpm Temp0,Z+
2
  lpm Temp1,Z


> Dann stehen die High-Bytes in Temp0, die Low-Bytes in Temp1?

 Nein.
 Low in Temp0, High in Temp1.


> Nur lese ich dann nicht die Nächste Adresse ein, wenn ich ZL erhöhe?

 Nein, du liest zuerst das niedrige Byte aus der WORDADRESSE, dann
 das höherwertige Byte. Du hast die WORDADRESSE mit (2*Tabelle)
 in eine BYTEADRESSE umgewandelt.

 In der Tabelle steht:
 .dw 960                  ;* HEX 0x03C0
 wird so übersetzt:
 .db 0xC0, 0x03

 und  wird auch so gelesen...

: Bearbeitet durch User
von Thomas F. (igel)


Lesenswert?

Ein kleines Beispiel aus einem Drehzahlmesser-Projekt von mir:
1
.def t1cnt_h = r6    ;Input-Capture-Werte von Timer1
2
.def t1cnt_l = r7    ;Nach diesen Werten soll gesucht werden
3
.def tabellenwert_h = r8  ;Entspricht den X-Werten d Tabelle
4
.def tabellenwert_l = r9
5
.def drehzahl_h = r10    ;Entspricht den Y-Werten
6
.def drehzahl_l = r11
7
8
;....
9
  drzr_0:
10
  ldi ZL, low( 2 * ctabelle )  
11
  ldi ZH, high( 2 * ctabelle )
12
  drzr_1:      
13
  lpm tabellenwert_l, Z+
14
  lpm tabellenwert_h, Z+
15
16
  cp  t1cnt_l, tabellenwert_l    ;Word-Vergleich mit
17
  cpc t1cnt_h, tabellenwert_h    ;dem Capture-Wert
18
19
  brcs drzr_2  ;Treffer: Capture-Wert ist größer als Tabelle
20
21
  adiw  ZH:ZL, 2  ;kein Treffer: 2. Wert überspringen
22
  rjmp drzr_1
23
24
  drzr_2:
25
  sbiw ZH:ZL, 4    ;Zum vorherigen Drehzahlwert springen
26
  lpm drehzahl_l, Z+  ;und Ergebnis lesen
27
  lpm drehzahl_h, Z+
28
  ret
29
      
30
ctabelle:      
31
.dw 600,12500
32
.dw 620,12097
33
.dw 640,11719
34
.dw 660,11364
35
.dw 680,11029
36
.dw 700,10714
37
.dw 720,10417
38
.dw 740,10135
39
.dw 760,9870
40
;usw

von Daniel B. (daniel10)


Lesenswert?

Thomas F. schrieb:
> Ein kleines Beispiel aus einem Drehzahlmesser-Projekt von mir:
> .def t1cnt_h = r6    ;Input-Capture-Werte von Timer1
> .def t1cnt_l = r7    ;Nach diesen Werten soll gesucht werden
> .def tabellenwert_h = r8  ;Entspricht den X-Werten d Tabelle
> .def tabellenwert_l = r9
> .def drehzahl_h = r10    ;Entspricht den Y-Werten
> .def drehzahl_l = r11
>
> ;....
>   drzr_0:
>   ldi ZL, low( 2 * ctabelle )
>   ldi ZH, high( 2 * ctabelle )
>   drzr_1:
>   lpm tabellenwert_l, Z+
>   lpm tabellenwert_h, Z+
>
>   cp  t1cnt_l, tabellenwert_l    ;Word-Vergleich mit
>   cpc t1cnt_h, tabellenwert_h    ;dem Capture-Wert
>
>   brcs drzr_2  ;Treffer: Capture-Wert ist größer als Tabelle
>
>   adiw  ZH:ZL, 2  ;kein Treffer: 2. Wert überspringen
>   rjmp drzr_1
>
>   drzr_2:
>   sbiw ZH:ZL, 4    ;Zum vorherigen Drehzahlwert springen
>   lpm drehzahl_l, Z+  ;und Ergebnis lesen
>   lpm drehzahl_h, Z+
>   ret
>
> ctabelle:
> .dw 600,12500
> .dw 620,12097
> .dw 640,11719
> .dw 660,11364
> .dw 680,11029
> .dw 700,10714
> .dw 720,10417
> .dw 740,10135
> .dw 760,9870
> ;usw


Hallo.

Habe das mal eben am Simulator nachgespielt.

ldi ZL,LOW (2*Tabelle)
ldi ZH,HIGH (2*Tabelle)
ldi Temp0,0
add ZL,Temp0

lpm Temp1,Z+
lpm Temp2,Z

Tabelle:
.dw 960
.dw 1400

Nun steht in Register Temp1: 03 Highbyte
und Temp2                  : C0 Lowbyte
Also 960.
Wenn ich jetzt an den zweiten Wert in der Tabelle kommen will, muss ich 
ZL
um 2 erhöhen, richtig?
Dann könnte ich ja auch so vorgehen:

ldi ZL,LOW (2*Tabelle)
ldi ZH,HIGH (2*Tabelle)
lsl Temp0  ; Wert x2
add ZL,Temp0

lpm Temp1,Z+
lpm Temp2,Z
Oder würde das jemand anders und besser machen?

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Daniel B. schrieb:
> lpm Temp1,Z+
> lpm Temp2,Z
> Oder würde das jemand anders und besser machen?

 So:
1
 lpm Temp1,Z+
2
 lpm Temp2,Z+

 Und Z-Reg zeigt auf nächstes Byte, bzw. auf LoByte nächstes Word...

: Bearbeitet durch User
von Daniel B. (daniel10)


Lesenswert?

Ich möchte ja nur einen .dw Wert einlesen. Die anderen brauche ich ja 
nicht.
bzw. brauche ich schon, aber lese ja nur einen Wert und dann nicht mehr, 
solange der Motor läuft.

Dann wäre das richtig ja? Am Simulator funktioniert das mit + und ohne 
+.

Denke ich hab es verstanden :-)

: Bearbeitet durch User
von Thomas F. (igel)


Lesenswert?

Marc V. schrieb:

> So:
1
> lpm Temp1,Z+
2
> lpm Temp2,Z+

>  Und Z-Reg zeigt auf nächstes Byte, bzw. auf LoByte nächstes Word...

Und diese Lösung hat noch den Vorteil dass das Z-Register als 16-Bit 
Register hochgezählt wird. Man muss sich also keine Gedanken um einen 
Überlauf von ZL bei 255->0 machen um dann händisch ZH hochzuzählen.

von S. Landolt (Gast)


Lesenswert?

> ldi ZL,LOW (2*Tabelle)
> ldi ZH,HIGH (2*Tabelle)
> lsl Temp0  ; Wert x2
> add ZL,Temp0

Das geht bei Carry schief.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

S. Landolt schrieb:
> Das geht bei Carry schief.

 Das geht immer schief, es sei denn, man will explizit einen Offset
 von +127 / -128 zur aktuellen Adresse dazuaddieren.

: Bearbeitet durch User
von Daniel B. (daniel10)


Lesenswert?

Hmm...
Aber wenn ich jetzt +2 mache, hab ich ja das Problem, das wenn ich eine
1 gespeichert habe, eine 3 habe. Dann würde ich ja einmal low und high 
von zwei verschieden Werten lesen.

Und solange meine Zahl die ich speichere maximal 10 ist, bekomm ich ja 
auch kein Carry gesetzt.

Bin aber für bessere Vorschläge offen :-)

Könnte ich nicht adc, also add with carry einbauen?
Hab das mit dem lsl aus dem Tutorial entnommen, jetzt weiß ich auch, 
warum das auf 127 Werte begrenzt ist, eben wegen lsl, stimmts? :-)

: Bearbeitet durch User
von S. Landolt (Gast)


Lesenswert?

Ich meinte Carry bei dem add, und das ist davon abhängig, ob Tabelle 
kurz vor einer 256-er Grenze liegt; ein eventuelles Carry muss dann also 
zu ZH hinzuaddiert werden.

von S. Landolt (Gast)


Lesenswert?

Ich habe meist ein Register reserviert, in welchem 0 steht, und das 
nenne ich auch null:
1
 ldi ZL,LOW (2*Tabelle)
2
 ldi ZH,HIGH (2*Tabelle)
3
 lsl Temp0  ; Wert x2
4
 add ZL,Temp0
5
 adc ZH,null
Es ginge aber auch
1
 ...
2
 add  ZL,Temp0
3
 brcc pc+2
4
  inc ZH

von Thomas F. (igel)


Lesenswert?

Daniel B. schrieb:
> Aber wenn ich jetzt +2 mache, hab ich ja das Problem, das wenn ich eine
> 1 gespeichert habe, eine 3 habe. Dann würde ich ja einmal low und high
> von zwei verschieden Werten lesen.
>
> Und solange meine Zahl die ich speichere maximal 10 ist, bekomm ich ja
> auch kein Carry gesetzt.

Verstehe jetzt nicht genau was du meinst.

Wenn deine Tabelle nur Werte <256 enthält dann nimm einfach .db für die 
ganze Tabelle. Wenn die Werte größer werden dann nimm .dw für alle 
Werte. Das HI-Byte für Werte <256 im Speicher ist dann eben null. Aber 
dein Programm kommt nicht durcheinander.


S. Landolt schrieb:
> add ZL,Temp0
> adc ZH,null

Das wird übrigens hier allgemein erklärt:
https://www.mikrocontroller.net/articles/AVR_Arithmetik#16_Bit_.2B_16_Bit

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Bei mir kommts bisschen auf die Geschwindigkeit an; ich hab's so 
gemacht:
1
    in r30,0x05  ; read ADCH  = get audio sample
2
    ldi r31, hi8(square_table_l)
3
    lpm r16,z
4
    inc r31
5
    lpm r17,z ;  (ADCH-128)^2  now in R17:R16

Es gibt da einfach 2 Tabellen, in der einen stehen die unteren 8 Bit, in 
der anderen die oberen 8 bit. Beide Tabellen sind 256 byte voneinander 
entfernt, daher der "inc r31". Die Tabellen fangen auch jeweils an einer 
glatt durch 256 teilbaren Adresse im Speicher an, also braucht man bei 
den Offsetberechnungen kein carry zu beruecksichtigen. Laeuft :-)

Gruss
WK

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Daniel B. schrieb:
> Könnte ich nicht adc, also add with carry einbauen?
> Hab das mit dem lsl aus dem Tutorial entnommen, jetzt weiß ich auch,
> warum das auf 127 Werte begrenzt ist, eben wegen lsl, stimmts? :-)

 Ja, nur ist mir nicht ganz klar wo es bei dir happert.

 Um einen Wert (WORD) der sich auf Position 5 in der Tabelle
 befindet, auszulesen:
1
    ldi  zl, low(Tabelle * 2)    ;* Zeiger auf Tabellenanfang
2
    ldi  zh, high(Tabelle * 2)
3
    ldi  temp0, low(5)        ;* Offset in die Tabelle
4
    ldi  temp1, high(5)
5
    lsl  temp0          ;* WORDs in Tabelle, deswegen 2 Bytes pro Wert
6
    rol  temp1
7
    add  zl, temp0        ;* Offset dazuaddieren
8
    adc  zh, temp1        ;* Addieren und ev. Carry übernehmen
9
    lpm  temp0, Z+    ;* Low Byte übernehmen
10
    lpm  temp1, Z     ;* High Byte übernehmen
11
    ret
12
Tabelle:
13
.dw 0x0000, 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666

 War es das, was du wolltest ?

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.