Hallo alle zusammen, ich schreibe gerade ein Programm auf dem Atmega 8 in Assembler. Eine Funktion soll ein Zähler sein, der von 0 bis 50.000 zählt und den aktuellen Wert auf einem LCD Display anzeigt. Ich habe auch schon im Tutorial ein super Kapitel gefunden (LCD: Ansteuerung eines LC-Displays im 4bit-Modus), in dem sogar erklärt wird, wie man eine 16 bit Zahl, bestehend aus 2 8 bit registern, ausliest und anzeigt. Hier mal ein Ausschnitt: ; ** Zehntausender ** ldi temp1, '0'-1 lcd_number1: inc temp1 subi temp2, low(10000) sbci temp3, high(10000) brcc lcd_number1 subi temp2, low(-10000) sbci temp3, high(-10000) rcall lcd_data Ich bin mir mit der 16 bit Arithmetik allerdings noch etwas unsicher und habe noch ein paar Fragen: -Warum wird im obigen Beispiel einmal subi und einmal sbci verwendet? -Wie würde der Code aussehen, wenn ich zwei 8 bit Register als 16 bit Register verwenden möchte und dort +1 rechnen möchte? "inc r16" wird wohl nicht gehen. Ich hoffe meine Beschreibung ist ausführlich genug und ihr versteht, was ich meine. Liebe Grüße René
René schrieb: > wenn ich zwei 8 bit Register als 16 bit > Register verwenden möchte und dort +1 rechnen möchte? adiw r24, 1
René schrieb: > -Warum wird im obigen Beispiel einmal subi und einmal sbci verwendet? sbci berücksichtigt den Übertrag (carry-flag) der bei subi entstanden sein kann. > -Wie würde der Code aussehen, wenn ich zwei 8 bit Register als 16 bit > Register verwenden möchte und dort +1 rechnen möchte? "inc r16" wird > wohl nicht gehen. inc r16 brne weiter inc r17 weiter: ...
Einige Register können zwecks Addition zu 16-Bit Paaren zusammengefasst werden. Beispiel (addiere 1 zum Registerpaar R24:R25) ADIW r25:24, 1 http://www.atmel.com/webdoc/avrassembler/avrassembler.wb_ADIW.html Befehlsübersicht zum Durcharbeiten: http://www.atmel.com/webdoc/avrassembler/avrassembler.wb_instruction_list.html
René schrieb: > -Warum wird im obigen Beispiel einmal subi und einmal sbci verwendet? Weil's eben die Umsetzung von 16Bit Arithmetik auf einer 8Bit Maschine ist. Da muss man Überträge machen (das passiert bei allen Additions- und Subtraktionsbefehlen automatisch) und die in der höherwertigen Stelle dann auch berücksichtigen. Das passiert allerdings nicht automatisch, sondern nur dann, wenn man eben genau die Operation verwendet, die das tut. Also sbci statt subi. > -Wie würde der Code aussehen, wenn ich zwei 8 bit Register als 16 bit > Register verwenden möchte und dort +1 rechnen möchte? "inc r16" wird > wohl nicht gehen. Doch, geht zur Not auch. Nur leider setzt die inc-Operation das Übertragsflag eben gerade nicht. Bei inc noch nicht wirklich schlimm, denn man kann hier auf's Zeroflag ausweichen, denn ein Übertrag ist genau dann erforderlich, wenn das Ergebnis für die Stelle 0 ist. Nur leider gibt es keine Operation, die so einen "Übertrag im Zeroflag" mitaddieren könnte. Man muss sich also mit einer zusätzlichen Verzweigung behelfen. Also etwa sowas bauen: inc R16 brne PC+2 inc R17 Damit kostet die 16Bit-Operation allerdings drei Takte statt der üblichen zwei. Der Vorteil ist allerdings: dieses Konstrukt funktioniert mit allen Registern. Wenn es nur mit R16..R31 funktionieren muss, dann wird man eher das verwenden: subi R16,Low(-1) sbci R17,High(-1) Das braucht nämlich nur zwei Takte. Der Trick ist hier, dass statt 1 zu addieren -1 subtrahiert wird. Das Ergebnis ist das gleiche, allerdings wird das Carryflag nicht so beeinflußt, wie man es von einer Addition erwartet, sondern "umgekehrt". Das ist aber kein Problem, wenn es entweder keine weiteren Stellen gibt oder für die weiteren Stellen einfach nach der gleichen Methode weiter gerechnet wird. Beispiel für inc(32Bit-Wert): subi R16,Byte1(-1) sbci R17,Byte2(-1) sbci R18,Byte3(-1) sbci R19,Byte4(-1) Und letztlich kann man für die Registerpaare R25:R24..R31:R30 auch noch adiw verwenden, wie im Thread schon gesagt wurde. Diese Operation hat allerdings gegenüber der vorigen Methode nur zwei marginale Vorteile: sie setzt das Carryflag, wie man es von einer Addition erwartet und sie braucht zwei Bytes weniger Flash. Bezüglich der Rechengeschwindigkeit ist sie hingegen leider nicht schneller als die subi/sbci-Methode. Und dazu kommt noch, dass auch ihr Wertebereich stark eingeschränkt ist, das geht nämlich nur mit Operanden im Bereich von 0..63. All das und auch viele weitere Details findest du in der "Instruction set reference". Sozusagen die Bibel für Assemblerprogrammierer. Lesen und verstehen musst du sie selber.
Hier wird die Sache deutlich ausführlicher erklärt. Ist zwar für 8051 ändert aber am Prinzip nichts: http://www.edsim51.com/8051Notes/8051/16bitAddition.html
Danke für die zahlreichen Antworten. Ich fasse zusammen: 1. > adiw r25:r24, 1 ist der einzige Befehl, der sich entsprechend SUBI und SBCI verhält und r25 und r24 zu einem Registerpaar zusammenfasst. Wenn r24 "voll ist" incrementiert er automatisch r25. Allerdings kann man nur Summanden bis +63 damit rechnen und er funktioniert nur mit den oberen 4 Registerpaaren. 2. > inc r16 > brne weiter > inc r17 >weiter: ... Die Rechnung wäre so wie bei 1., nur dass ich es dann "von Hand" rechnen würde: Sobald r16 übergelaufen ist, addiere ich r17 3. >Wenn es nur mit R16..R31 funktionieren muss, dann wird man eher das >verwenden: > subi R16,Low(-1) > sbci R17,High(-1) Ich subtrahiere also, anstatt zu addieren. Dann müsste ich noch mein Ergebnis von 65535 abziehen, um den aktuellen Zählerstand zu erhalten. Habe ich das so richtig verstanden? Und danke für die nützlichen Links, die habe ich mir gleich mal zum Nachschlagen gespeichert. Liebe Grüße
Hi Nein Statt 1+1 rechnest Du 1-(-1) und bei Beiden kommt das Gleiche raus. Du musst nur Deinen Summanden 'umdrehen'. MfG
Patrick J. schrieb: > Hi > > Nein > > Statt 1+1 rechnest Du 1-(-1) und bei Beiden kommt das Gleiche raus. > Du musst nur Deinen Summanden 'umdrehen'. > > MfG ah cool danke hab´s gerade ausprobiert
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.