Hallo
Ich hab das Forum schon durchsucht und mir einige Codes angeschaut, habe
aber irgendwie keine befriedigende Lösung gefunden.
Ich möchte ein Register bis 1000 hoch- bzw. runterzählen über
Tastendruck (Befehle dec und inc), gleichzeitig soll die Zahl im Display
ausgegeben werden und anschließend mit dieser Zahl gearbeitet werden
können im speziellen Fall soll sie einer Verzögerung dienen sprich sie
wird einfach wieder runtergezählt.
Das alles hab ich schon hinbekommen mit einem normalen Register nur geht
das dann ja leider mal nur bis 255. Jetzt hab ich mir schon jede Menge
überlegt mit Überlauffunktionen etc, damit das Ganze auf zwei Register
verteilt wird. Problem ist nur, dass das dann viel Speicher und Zeit
braucht. Schöner währe es während des Zählvorgangs nicht noch prüfen zu
müssen ob die Zahl auch nicht 255 übersteigt sondern wenn man einfach
ein Register hat, dass bis 1000 zählen kann.
Es gibt da diese Z-Register (r30+31) nur habe ich diese in diesem
Zusammenhang noch nirgen gesehen, immer nur als Zeigerregister. Kann man
diese Register auch als ein einziges 16bit Register verwenden? und wenn
ja wie, gibts da codesamples oder ist das so trivial, dass ich darüber
längst gestoplert sein müsste?
vielen dank für die Hilfe
Gruß
Matze
Bevor man sich hier in den Untiefen der Binärarythmetisk stürzt,
empfehle ich dem Anfänger bei sowas selbst Hand anzulegen und in BCD
zählen.
Aber als Tipp für die Zukunft solltest du dir angewöhnen gleich in Hex
zu arbeiten und erst im letzten Schritt nach Dezimal umrechnen. Du
willst also von 0 - 0x3e8 zählen. Den Dezimalwert erhälst du
Stellenweise, wenn du den Wert immer durch 10 (0x0a) teilst.
0x3e8 / 0xa = 0x64 rest 0
0x064 / 0xa = 0x0a rest 0
0x00a / 0xa = 1 rest 0
Die "1" mit den drei "0" sind dein Ergebnis bei der Wandlung nach
dezimal. Aber wie ich Eingangs bereits sagte: dem Anfänger empfehle ich
erstmal mit BCD zu arbeiten. Das ist aufwenider aber weniger
kompliziert.
Es gibt bei einem 8-Bit-Controller nunmal nur 8-Bit-Register. Punkt.
Wenn Du aus zwei solcher Register ein 16-Bit-Register machen willst,
dann musst Du in Kauf nehmen, dass i.d.R. zwei Operationen erforderlich
sind, um eine Addition oder Subtraktion zu machen. Selbstverständlich
kannst Du aber r31 und r30 (und natürlich auch r25+r24, r27+r26 und
r29+r28) für beliebige Zwecke nutzen, wenn Du sie nicht gerade als
Zeiger benötigst. Und Du kannst dann natürlich auch mit adiw oder sbiw
darauf zugreifen.
Allerdings solltest Du beachten, dass das gegenüber
Inkrementieren/Dekrementieren und Carry-Flag-Addieren/Subtrahieren
keinerlei Zeitvorteil mitbringt, da sbiw und adiw 2 Zyklen brauchen (inc
bzw. dec und sbc bzw. adc nur je einen, macht zusammen auch jeweils 2
Zyklen...).
Niels Hüsken wrote:
> Bevor man sich hier in den Untiefen der Binärarythmetisk stürzt,> empfehle ich dem Anfänger bei sowas selbst Hand anzulegen und in BCD> zählen.
Ist hoffentlich nicht wirklich Dein Ernst, oder? Dem OP ist die
"normale" Zählerei schon zu langsam, und er kommt mit einem einzigen
Übertrag schon ins Schleudern, und Du willst ihm BCD-Zahlenspielchen
empfehlen, mit denen er sich nicht nur (beim Zählen bis 1000) mit jedem
Inkrement drei Überträge einhandelt, sondern auch noch 3
Vergleichsoperationen? Also bitte...
@Matthias:
Schau bitte mal ins Instruction Set Summary oder in die Hilfe vom
AVRStudio (falls Du das, was ich vermute, noch nicht getan hast). Da
stehen bei den Subtraktions- und Additionsbefehlen Beispiele, wie man
16-Bit-Werte behandelt.
Johannes M. wrote:
> Niels Hüsken wrote:>> Bevor man sich hier in den Untiefen der Binärarythmetisk stürzt,>> empfehle ich dem Anfänger bei sowas selbst Hand anzulegen und in BCD>> zählen.> Ist hoffentlich nicht wirklich Dein Ernst, oder? Dem OP ist die
Ich bin der Meinung, BCD ist für Anfänger einfacher. Das es Aufwendiger
ist, steht ausser Frage, aber es ist weniger kompliziert...
Niels Hüsken wrote:
> Ich bin der Meinung, BCD ist für Anfänger einfacher. Das es Aufwendiger> ist, steht ausser Frage, aber es ist weniger kompliziert...
BCD ist das allerletzte! Einen Rechner im Dezimalsystem rechnen zu
lassen ist völlig sinnfrei. Anfänger sollten auf jeden Fall sofort
anfangen, binär bzw. hexadezimal zu denken. Da führt kein Weg dran
vorbei! Und Zählen in Dezimal ist der allergrößte Unfug. Gerade beim
Zählen muss man sich schließlich überhaupt nicht um das Zahlensystem
kümmern. Dafür gibt es schließlich die Befehle adc, sbc und für
Vergleiche cpc. Und für alle stehen genau für den aktuellen
Anwendungsfall Beispiele im Instruction Set Summary. Und für die Eingabe
im Code kann man schließlich immer noch Dezimalzahlen benutzen (und bei
16-Bit-Werten low() und high()).
Matthias wrote:
> Das alles hab ich schon hinbekommen mit einem normalen Register nur geht> das dann ja leider mal nur bis 255. Jetzt hab ich mir schon jede Menge> überlegt mit Überlauffunktionen etc, damit das Ganze auf zwei Register> verteilt wird. Problem ist nur, dass das dann viel Speicher und Zeit> braucht.
Wow, Du kannst also 100.000 neue Werte pro Sekunde ablesen!!!
Ich kann nur etwa 5.
In der Regel zählt eine CPU viel zu schnell und man muß große
zusätzliche Zeitverzögerungen einbauen, damit man überhaupt was sieht
und auch zum Entprellen.
Peter
Johannes M. wrote:
> @Niels:> Nö, ich kann tatsächlich keinen Sinn in Deinen Aussagen entdecken,> obwohl ich es gern würde... Vielleicht kann die Wand Dich ja> verstehen...
Aha, ok, ich habe mich auch mehr auf die Umwandlung nach Dezimal
bezogen, als auf die Nutzung einfacher Funktionen und Grundrechenarten.
Aber die Wandlung von Hex nach Dezimal ist wesentlich komplexer, als die
von BCD nach Dezimal, da hier praktisch keine Wandlung mehr stattfinden
muss.
das hilft mir doch schonmal sehr weiter. nur ich bin noch zu sehr am
anfang um genau zu verstehen was du machst. arbeitest du jetzt mit den
X, Y, Z-registern? wennja, wie definiere ich die, lade da werte ein etc.
wahrscheinlich alles anfängerfragen aber ich finde in den tutorials
immernur einen bezug zu der verwendung als pointer und das hilft mir
irgendwie nicht weiter. kann man mir sonst vielleicht ne gute quelle
nennen wo ich das nachlesen kann mit diesen zeiger-registern r30-r31
usw?
Peter Dannegger wrote:
> Wow, Du kannst also 100.000 neue Werte pro Sekunde ablesen!!!> Ich kann nur etwa 5.
naja, ich machs halt so, dass ich den taster abfrage, dann entscheide ob
ich einen hochzähle, einen runterzähle oder im programmtext weiter gehe
("enter"), nach dem weiterzählen gebe ich dann den wert über das display
aus und starte die abfrage von neuem. kann man alles sicherlich
eleganter lösen nur bin ich grade mal ne woche dabei mich auch nur
ansatzweise damit zu beschäftigen und bin schon froh soweit alleine
gekommen zu sein ;-)
Die Nutzung eines pseudo-16Bit registers bringt dir nichts, weil du
damit nicht arbeiten kannst (keine Vergleiche oder ähnliches). Sie sind
tatsächlich auschliesslich dazu gedacht, auf den Speicher zu zeigen.
Du kommst nicht dran vorbei 8Bit Register zu paaren. Wie man das macht,
steht in einem Link, den Johannes schon vorher gepostet hatte.
Matthias wrote:
> naja, ich machs halt so, dass ich den taster abfrage, dann entscheide ob> ich einen hochzähle, einen runterzähle oder im programmtext weiter gehe> ("enter"), nach dem weiterzählen gebe ich dann den wert über das display> aus und starte die abfrage von neuem. kann man alles sicherlich> eleganter lösen
Um Eleganz geht es nicht.
Du hattest aber behauptet, 16Bit Operationen dauern zu lange und
benötigen zuviel Speicher, aber das ist keineswegs der Fall.
Peter
Hi
X, Y und Z sind Namem für zusammengefasste Registerpaare r26:r27,
r28:r29 und r30:r31. Die Verwendung als Pointer resultiert in den
Adressierungsarten für die Loadbefehle 'ld/ldd' und den Zugriff per
'lpm' auf den Flashspeicher. Ansonsten sind das ganz stinknormale
Register wie r16,r17... . Definiert sind die in den entsprechenden
'XYZdef.inc-Dateien'. D.h. du brauchst da nichts selbst definieren. Auf
die einzelnen 8-Bit-Register kannst du auch mit beispielsweise XL(r26)
oder XH(r27) zugreifen.
Für deine Zwecke würden sich die Befehle adiw/sbiw anbieten. Mit diesen
Befehlen lassen sich von X, Y, Z sowie r24:r25 0..63 addieren bzw.
subtrahieren.
Die obere Grenze kannst du wie Johannes oben beschrieben hat erkennen.
Null kann z.b. so getestet werden
1
2
push XL
3
or XL,XH
4
pop XL
5
breq... oder brne...
@Johannes sbc r17,0/adc r17,0 gibt es nicht. Geht nur mit Registern.
MfG Spess
Spess53 wrote:
> @Johannes sbc r17,0/adc r17,0 gibt es nicht. Geht nur mit Registern.
Jau, hab ich auch grad gemerkt. Und mit dec und inc gehts übrigens
natürlich auch nicht, weil die das Carry nicht beeinflussen. Muss also
korrekt(er) heißen:
so, falls es noch jemanden interessier (andere anfänger?) ich habs jetzt
einfach so gemacht:
ich zähle das eine register bis 99 hoch, dann fängt es wieder von vorne
an und ein zweites register ist auf 01 gesetzt. bei der nächsten runde
wird das zweite register dann auch 02 usw. das lässt sich dann einfach
in zwei teilen im display darstellen und ich kann damit den timer dann
auch ablaufen lassen, wenn ich die verstrichene zeit des zweiten
registers ainfach mal hundert nehme.
denke das sind basics die den meisten hier bekannt sind aber ich musste
das erstmal so rausfinden und bin damit auch ganz zufrieden. für andere
rechenoperationen eignet sich das konstrukt dann vielleicht nicht mehr
aber für meinen fall ist das ideal
auf jeden fall danke ans forum
matze
Schön, wenns läuft. Damit hast Du jetzt allerdings das, was Du
eigentlich vermeiden wolltest (nämlich eine ständige Abfrage, ob der
Wert im Register "überläuft"), wieder drin, hast allerdings den Vorteil,
dass Du vor der Ausgabe nicht mehr großartig umrechnen musst (wenn Dir
das wichrtiger ist...).
Aber ich denke, Du wirst das, wenn Du tiefer in die Materie einsteigst,
auch anders machen. Es ist nur wichtig zu wissen (und das führte
letztendlich zu dem "Missverständnis" mit Niels), dass ein Controller
nur binär arbeiten kann, und alles, was in Zahlensystemen gerechnet
werden soll, die nicht direkt ins Binärsystem umschreibbar sind (also
deren Basis keine Potenz von 2 ist), ziemlich aufwändig ist. Bei Deiner
Version musst Du jetzt das erste Register inkrementieren, dann eine
Abfrage machen, ob 99 überschritten ist, falls ja, das Register zu Null
setzen und das andere inkrementieren. Im Gegensatz dazu ist die
Binär-Variante mit genau zwei Befehlen (und zwei Taktzyklen) deutlich
effizienter (was allerdings, wie Peter schon richtig sagte, zumindest
bei Tasten eher unkritisch ist, weil da die Auswertung sowieso i.d.R.
viel schneller ist als die Ereignisfolge).
Anmerkung:
Bei der Dekrementierung hatte ich noch was vergessen. Geht noch
einfacher, weils bei der Subtraktion einen "Subtract Immediate With
Carry"-Befehl gibt und man sich so das leere Register sparen kann:
1
subi r16, 1
2
sbci r17, 0
Aber das nur am Rande. Hab mal wieder gemerkt, dass ich mich viel zu
lange nicht intensiv genug mit Assembler befasst habe. Wird mal wieder
Zeit...
Hi Leute :-D
Bin grad zufällig beim stöbern hier auf diesen Thread gestoßen. Ich
befasse mich seit ca. nem halben Jahr mit der ASM Programmierung und
genau mit diesem Problem hier war ich ebenfalls konfrontiert. Falls es
mal jemand brauchen sollte. :-)
Hab das bisher immer so gelöst:
.equ c1 = 10000 ;Zählerkonstante festlegen
.
bla bla bla Eingang/Ausgang Programmcode usw....
.
.
.
ldi r25, HIGH(c1) ;Konstante in Register H/L
ldi r24, LOW(c1)
Loop1:
sbiw r24, 1 ;Registerwert um 1 verringern
nop
nop
nop
nop
brne Loop1 ;wenn null dann weiter sonst wieder zu Loop1
.
Programmcode
Funktioniert super für diverse Zeitverzögerungen oder für
Tasterentprellung. Hier kann bis max. 65536 gezählt werden. Noch ein
paar "nop"s dazwischen und das ganze vermehrfacht sich dann
dementsprechend (hier x4). Die "nop"s kann man natürlich auch weglassen,
ist nur ein Beispiel! Gibt sicher auch andere Lösungen, aber ich hab mir
bisher alles selbst mit Internet-Lektüre beigebracht. Auf die
komplizierten Lösungen sollte man als Anfänger denk ich erst mal
verzichten, da man sich schnell in was verzetteln kann. Lieber einfach
und solide, dafür lernt man die Funktion des µC besser kennen find ich.
Gruss Sven
Johannes M. schrieb:> inc r16 ;Low-Byte inkrementieren> adc r17, 0 ;High-Byte plus Carry
Seit wann setzt inc das Carryflag ?
Niels Hüsken schrieb:> Aber als Tipp für die Zukunft solltest du dir angewöhnen gleich in Hex> zu arbeiten und erst im letzten Schritt nach Dezimal umrechnen
Das halte ich für Quatsch. Wenn ich Dezimal bis 1000 zählen will,
schreibe ich auch 1000 hin, umrechnen lass ich das vom Assembler.
>pc+1 beschreibt die Adresse des folgenden Befehls. Man könnte es auch so>schreiben:>rjmp L1>L1:
Ok...kapiert! :-)
da fällt mir grad noch was ein....ich meine mal irgendwo in den
unendlichen Weiten des I-Net´s gelesen zu haben, dass man das HIGH
Register zuerst laden soll, ist das richtig? Oder bezieht sich dass nur
auf den Stack beim initialisieren?
z.B. so...
ldi r25, HIGH(1000)
ldi r24, LOW(1000)
oder....
ldi r24, LOW(1000)
ldi r25, HIGH(1000)
oder ist das schlicht egal?
Sven schrieb:> da fällt mir grad noch was ein....ich meine mal irgendwo in den> unendlichen Weiten des I-Net´s gelesen zu haben, dass man das HIGH> Register zuerst laden soll, ist das richtig?
Das ist richtig.
Genauso umgekehrt: Erst das Low Register auslesen, dann erst das High
Der Grund dafür ist einfach: Bei einigen Register-Pärchen gibt es eine
Logik im µC, die die Register verriegelt. Zb die ADC Register ADCH,
ADCL.
Durch den Lesezugriff auf ADCL wird das ADC-Werte Registerpärchen gegen
Veränderungen verriegelt. Erst der Lesezugriff auf ADCH hebt diese
Verriegelung wieder auf. Dieser Mechanismus soll sicher stellen, dass
die INhalte im H und L Register auch wirklich von derselben Messung
stammen. Sonst könnte es passieren, dass du das eine Register ausliest
und just in diesem Moment ist der ACD zb im Free Running Modus mit einer
neuen Messung fertig und beschreibt die Register neu. Liest du dann das
andere Register aus, dann hast du 1 byte von der alten Messung und das
andere Byte von der neuen Messung.
Am einfachsten ist es daher sich einfach fix an diese Reihenfolge zu
halten, selbst wenn sie bei einem Registerpärchen nicht notwendig wäre.