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
Ich denke, ich rede gegen eine Wand...offensichtlich willst du nicht verstehen, was ich meine...
Hier mal die drei erforderlichen Operationen (ohne Gew(a)ehr):
1 | ;Inkrementieren 16 Bit: |
2 | inc r16 ;Low-Byte inkrementieren |
3 | adc r17, 0 ;High-Byte plus Carry |
4 | |
5 | ;Dekrementieren 16 Bit: |
6 | dec r16 ;Low-Byte dekrementieren |
7 | sbc r17, 0 ;High-Byte minus Carry |
8 | |
9 | ;Vergleich 16 Bit: |
10 | ldi r18, high(1000) ;High-Byte vom Vergleichswert in Register |
11 | cpi r16, low(1000) ;Low-Byte vergleichen |
12 | cpc r17, r18 ;High-Byte mit Carry vergleichen |
13 | brlo irgendwo ;Verzweige irgendwohin, wenn kleiner als Vergleichswert |
@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...
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:
1 | ;Inkrementieren 16 Bit: |
2 | clr r19 ;Register mit 0 vorbelegen |
3 | subi r16, -1 ;Low-Byte inkrementieren |
4 | adc r17, r19 ;High-Byte plus Carry |
5 | |
6 | ;Dekrementieren 16 Bit: |
7 | clr r19 ;Register mit 0 vorbelegen |
8 | subi r16, 1 ;Low-Byte dekrementieren |
9 | sbc r17, r19 ;High-Byte minus Carry |
Sorry, war meine Blödheit...
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...
Mal ne blöde Frage: ADIW und SUBIW machen doch Wordarithmetik. Oder verstehe ich da was falsch? guido
@ guido (Gast) >ADIW und SUBIW machen doch Wordarithmetik. >Oder verstehe ich da was falsch? Das siehst du richtig. MFG Falk
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
>Kleiner Tipp: 2x nop == rjmp pc+1
Was bedeutet hier rjmp pc+1
rjmp ist klar aber was macht er mit == pc+1 ??
Hallo, ich würde das in etwa so schreiben. (nicht getestet)
1 | ldi r16,low(1000) |
2 | ldi r17,high(1000) |
3 | |
4 | |
5 | clr xl |
6 | clr xh |
7 | |
8 | up: |
9 | cp xl,r16 |
10 | cpc xh,r17 |
11 | breq _1000erreicht |
12 | adiw x,1 |
13 | ... |
14 | |
15 | down: |
16 | tst xl |
17 | brne decx |
18 | tst xh |
19 | brne decx |
20 | ... |
21 | |
22 | |
23 | decx: |
24 | sbiw x,1 |
pc+1 beschreibt die Adresse des folgenden Befehls. Man könnte es auch so schreiben: rjmp L1 L1: ...
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.
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.