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
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
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 |
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
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
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
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.
> ldi ZL,LOW (2*Tabelle) > ldi ZH,HIGH (2*Tabelle) > lsl Temp0 ; Wert x2 > add ZL,Temp0 Das geht bei Carry schief.
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
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
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.
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 |
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
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.