Der muß aber manchmal sein, kenn ich von mir!Zitat:
Holzhammer war nicht gewollt
Gut gemacht bis jetzt,
Ich muß leider los (bin gerade im Büro, und sehe da PC an O:) )
melde mich später wieder, bin gespannt, wie weit Ihr kommt.
Gruß Sebastian
Druckbare Version
Der muß aber manchmal sein, kenn ich von mir!Zitat:
Holzhammer war nicht gewollt
Gut gemacht bis jetzt,
Ich muß leider los (bin gerade im Büro, und sehe da PC an O:) )
melde mich später wieder, bin gespannt, wie weit Ihr kommt.
Gruß Sebastian
Bis nachher Sebastian! *rette mich, ich kann das nicht erklären -> lol*
Also bräuchten wir noch ein Register, wo wir die Zahl der eingelesenen Zeichen aufbewahren. Und vergleichen ob diese Zahl = 6 ist.
(In unserem Fall). Wenn ja, Abbruch.
So in etwa?
Oh, hi Sebastian und auch wieder tschö *g* Genieß die letzten Arbeitsstunden noch ;)
Florian: Doch du kannst das :P
Ich hab nicht viel über cp und cpc rausgefunden, nur das cp die unteren Bits vergleicht und cpc die oberen.
Aber so richtig verstanden hab ichs nicht. Wo find ich denn die oberen und unteren Bits?
Hallo Tekeli!
So in etwa stimmt das, aber Du musst das, was Du zu Anfang in ZL und ZH lädst nur nochmal in die Register laden und plus die 6 Bytes rechnen!
Das ist dann die Endbeschränkung!
Ich möchte die Codes sehen! *lol*
*ich geh mal kurz was essen, bin gleich wieder da*
Hmm...ich hab das jetzt so gelöst:
Sorry, versteh die Befehle cp und cpc aber leider nicht (wegen untere Bytes und obere?) Aber mein Code geht auch.Code:;Programm
;CDurTonleiter rauf und runter spielen
.include "m8def.inc"
.def tmp = r16 ;Mein Universallregister
.def lpm_reg = r0 ;Mein lpm-Register
.def zaehler = r17 ;Mein Zählregister, prüft, ob das Wort zu Ende ist
.org 0x000
rjmp reset ;Interruptvektor "reset:"
reset:
;Stack einrichten
ldi tmp, HIGH(RAMEND) ;HIGH-Byte der obersten RAM-Adresse
out SPH, tmp
ldi tmp, LOW(RAMEND) ;Low-Byte der obersten RAM-Adresse
out SPL, tmp
ldi ZH, HIGH(daten1 * 2)
ldi ZL, LOW(daten1 * 2)
ldi zaehler, 0b00000000 ;Zähler auf 0 setzen
sei ;Interrupts zulassen
loop:
cpi zaehler, 0b00000110 ;Vergleich Zähler mit 6
breq loop ;wenn Zähler != 6, dann wieder zu "loop:" springen
einlesen:
lpm ;nächstes Byte des String nach r0 einlesen
mov tmp, lpm_reg ;Inhalt von R0 nach "tmp" kopieren
adiw ZL,1 ;Adresse des Z-Pointers um 1 erhöhen
inc zaehler ;Zähler um 1 erhöhen
rjmp loop ;wieder zurück zu "loop:"
daten1:
.db "Hallo!" ;immer eine gerade Anzahl an Bytes
Nachteil ist eben, dass von Anfang an klar sein muss, aus wieviel Zeichen dsa Wort besteht.
[edit]
Ich bin auch mal eben was essen.
Nochmal eine Anmerkung (wie gut, daß mein Chef jetzt feiern ist)
Ein String wie "hallo!" von Florian ist nichts anderes als 6 Bytes die hintereinander im Speicher stehen.
Der Assembler erkennt aber, daß es sich um eine Zeichenkette handelt und wandelt selber
jeden Buchstaben in ASCII Zahlen um. ASCII ist steinalt, hat aber bis heute überlebt,
weil es recht simpel ist. Solltet Ihr Euch damit noch nicht auseinandergesetzt haben
hier ist eine Tabelle, wo man schön entnehmen kann welcher Buchstabe, welchem Wert entspricht.
Der Assembler wandelt auch selber um wenn man das so schreibt:
db. 'H','a','l','l','o','!'
Das ist Praktisch, sonst müßten wir uns selber darum kümmern.
Das werden wir auch nicht bei unsere Tonleiter brauchen,
hier werden wir sicher irgendwelche Werte im Speicher ablegen, um unsere Frequenzen
abzuspeichern.
Der Florian hat es nur mit dem Hallo genommen, um in die Thematik einzusteigen, denke ich
Sinnvoll sind nur ASCII Zeichen, wenn man z.B. über ein Terminal mit dem µC komuniziert, oder irgendwas auf dem LCD ausgeben möchte.
Das ist aber im Moment nicht das Ziel unserer Übung.
So jetzt verschwinde ich hier lieber :-$
Gruß Sebastian
Hallo Sebastian!
Danke nochmal für Deine Nacherklärung! ;o)
@ Thomas:
Was verstehst Du derzeit nicht?
@ Tekeli:
Was verstehst Du derzeit nicht?
Ps:
Bisher wollte ich nur zeigen, wie man Daten, die man im AVR-Flash speichert (.DB bzw. .DW), ausliest und in ein anderes Register schiebt, mehr nicht! ;o)
Das ganze hat bisher noch nichts mit Tönen zu tun!
cp und cpc sind die wichtigsten Befehle im Assembler, und glaub mir Thomas, du hast
sie (zumindest cp) schon unbewußt benutzt!
cp hat aber nur Sinn in Verbindung mit SREG.
oder was meinst Du was die ganzen brne, breq usw. machen?
es sind keine Befehle für sich wenn Du Dir anschaust wieviele Takte sie brauchen, steht dort meistens 1/2 .
und warum? weil dort immer cp ausgeführt wird und jenachdem welcher Flag im SREG danach gesetzt (oder nicht gesetzt ist) wir gesprungen, oder halt nicht.
schreibe Dir ein Miniprogramm, wo Du zwei Register mit Werten fütterst.
Behandle sie dann mit hilfe von cp uns schaue, was sich im SREG so tut.
Schaue auch was die Bits von SREG zu bedeuten haben, und ändere die Zwei Werte im Register.
Dann wirst Du schon um einiges schlauer!
Gruß Sebastian
Na ihr Beiden, wie siehts aus?
Komt ihr voran?
Soll ich noch was erklären?
Ihr kennt doch auch cpi, oder?
ich dachte, die erste Teilaufgabe ist gelöst worden? Zwar nicht mit einer 16-Bit Adressenrechnung, wie das Florian vor hatte, aber es funzt. :)
Ist das richtig so?
So, da bin ich wieder vom essen.
Das mit cp und cpc, also wie das genau funktioniert, aber das test ich dann erstmal im Simulator aus, wie Sebastian meinte.Zitat:
@ Thomas:
Was verstehst Du derzeit nicht?
Und wir meinten ja, dass der String "Hallo" 6 Bytes hat, ne? Wieso passt der dann in ein 8 Bit Register? 8 Bit sind doch nur 1 Byte, also sehr viel kleiner als 6 Byte. Oder bring ich da nun was durcheinander?
cpi kennen wir schon. Hab ich auch oben in meinem Code verwendet, aber ich glaub, so wolltest du das ja nicht haben, oder?
Hallo Thomas!
Jedes Byte wird nacheinander in das r0 geladen, nicht der ganze String auf einmal!
Sonst müsstest Du ja nicht immer lpm ausführen!
Soll ich einen Beispielcode posten?
Ja, dass es nacheinander passiert, ist mir klar, aber am Ende kann in r16 ja nicht "Hallo!" stehen, oder? Denn "Hallo!" braucht ja nunmal 6 Bytes. Also steht am Ende im Register nur ein "!"?
Wenns zum Verständniss beiträgt ;) Die Teilaufgabe haben wir ja schon gelöst, also verrätst du ja nichts.Zitat:
Soll ich einen Beispielcode posten?
[edit]
Der Befehl
cp reg1, reg2
rechnet im prinzip reg2 - reg1, oder?
cpc funzt aber irgendwie anders, wie hab ich leider noch nicht rausgefunden.
Ja, ich wollte ja nur, dass ihr ungefähr den Ablauf versteht, wie man den Speicher ausliest!Zitat:
Ja, dass es nacheinander passiert, ist mir klar, aber am Ende kann in r16 ja nicht "Hallo!" stehen, oder? Denn "Hallo!" braucht ja nunmal 6 Bytes. Also steht am Ende im Register nur ein "!"?
Ok, hier kommt die Lösung!
Jetzt erklärt mir bitte die einzelnen Segmente des Codes!Code:.include "m8def.inc"
.def lpm_reg = r0
.def temp = r16
.equ daten_laenge = 6
reset:
stack: ; Stack
ldi temp , LOW (RAMEND) ; LOW-Byte
out SPL , temp
ldi temp , HIGH (RAMEND) ; HIGH-Byte
out SPH , temp
z_register:
ldi ZL , LOW (daten * 2) ; Z-Register laden, mit der Adresse der Daten
ldi ZH , HIGH (daten * 2)
main:
lpm ; Daten laden
mov temp , lpm_reg ; in temp verschieben
adiw ZL , 1 ; Z um eins erhöhen
ldi temp , LOW ((daten * 2) + daten_laenge) ; vergleiche LOW-Byte
cp ZL , temp
ldi temp , HIGH ((daten * 2) + daten_laenge) ; vergleiche HIGH-Byte
cpc ZH , temp
breq ende ; springe zu ende, wenn letztes Byte ausgelesen
rjmp main ; nochmal
ende: ; Endschleife
rjmp ende
daten: ; Daten
.DB "Hallo!"
Ich kann dir leider nicht sagen, was das hier bedeutet
Da ich das mit dem unteren und oberen Byte ja immer noch nicht verstanden habe :(Code:ldi temp , LOW ((daten * 2) + daten_laenge) ; vergleiche LOW-Byte
cp ZL , temp
ldi temp , HIGH ((daten * 2) + daten_laenge) ; vergleiche HIGH-Byte
cpc ZH , temp
So wie ich das jetzt verstanden habe, sind die Adressen selbst auch 16 Bit.
Die Adresse 0x020F z.B. besteht aus zwei Byte nähmlich:
0x02 - High Byte
0x0F - Low Byte
Der ATmega8 kann aber nur 8-Bit-Zahlen vergleichen. (richtig so?)
Deswegen verglechen wir erstmal Low-Bytes von der Adressen und dann High-Bytes. Siehe die Post von Florian um 13:23
Und wieso dann einmal cp und einmal cpc?
also with carry heißt doch dann mit Übertrag. Was bedeutet in dem Zusammenhang "Übertrag". Ich kenn Übertrag nur beim schriftlichen Rechnen, bspw. beim Addieren, wenn die oberen beiden Zahlen > 9 sind, dann muss man bei sagen wir mal 10 ne 0 hinschreiben (unterm strich) und dann 1 als übertrag, die wir dann mitaddieren.
Hallo, o weh, es kommt Knüppeldick!
Ich erlaube mir einen Auszug aus www.avr-asm-tutorial.net zu zitieren, damit
Ihr hoffe ich sieht was wir hier machen!
Thomas hat schon richtig erkannt, was cp macht, hat sich aber noch nicht mit SREGZitat:
Addition, Subtraktion und Vergleich
Ungeheuer schwierig in Assembler ist Addieren, Dividieren und Vergleichen. Zart-besaitete Anfänger sollten sich an dieses Kapitel nicht herantrauen. Wer es trotzdem liest, ist übermütig und jedenfalls selbst schuld.
Um es gleich ganz schwierig zu machen, addieren wir die 16-Bit-Zahlen zu den Registern R1:R2 die Inhalte von R3:R4 (Das : heißt nicht Division! Das erste Register gibt das High-Byte, das zweite nach dem : das Low-Byte an).
ADD R2,R4 ; zuerst die beiden Low-Bytes
ADC R1,R3 ; dann die beiden High-Bytes
Anstelle von ADD wird beim zweiten Addieren ADC verwendet. Das addiert auch noch das Carry-Bit dazu, falls beim ersten Addieren ein Übertrag stattgefunden hat. Sind sie schon dem Herzkasper nahe?
Wenn nicht, dann kommt jetzt das Subtrahieren. Also alles wieder rückwärts und R3:R4 von R1:R2 subtrahiert.
SUB R2,R4 ; Zuerst das Low-Byte
SBC R1,R3 ; dann das High-Byte
Wieder derselbe Trick: Anstelle des SUB das SBC, das zusätzlich zum Register R3 auch gleich noch das Carry-Bit von R1 abzieht. Kriegen Sie noch Luft? Wenn ja, dann leisten sie sich das folgende: Abziehen ohne Ernst!
Jetzt kommt es knüppeldick: Ist die Zahl in R1:R2 nun größer als die in R3:R4 oder nicht? Also nicht SUB, sondern CP, und nicht SBC, sondern CPC:
CP R2,R4 ; Vergleiche untere Bytes
CPC R1,R3 ; Vergleiche obere Bytes
Wenn jetzt das Carry-Flag gesetzt ist, kann das nur heißen, dass R3:R4 größer ist als R1:R2. Wenn nicht, dann eben nicht.
so richtig auseinander gesetzt
Gruß Sebastian
Also Thomas!
Ja klar! *lol*Zitat:
So wie ich das jetzt verstanden habe, sind die Adressen selbst auch 16 Bit.
Das Adressregister ist 16Bit, da man sonst die ganzen Flashbytes nicht aufrufen könnte, sondern nur 255, das wäre etwas wenig! ;o)
Genau richtig!Zitat:
Der ATmega8 kann aber nur 8-Bit-Zahlen vergleichen. (richtig so?) Deswegen verglechen wir erstmal Low-Bytes von der Adressen und dann High-Bytes.
Nochmal ganz langsam:
ldi temp , LOW ((daten * 2) + daten_laenge)
daten ist die Adresse, zu der gesprungen werden soll.
Das nimmt man wie gewohnt mal zwei.
Dazu addieren wir dann 6 (Bytes), um das Ende festzulegen.
Das vergleichen wir dann mit der Funktion cp mit ZL, dem LOWbyte.
Das ganze dann nochmal mit dem Highbyte.
Fertig, das ist alles!
Nichts fertig :(Zitat:
Nochmal ganz langsam:
ldi temp , LOW ((daten * 2) + daten_laenge)
daten ist die Adresse, zu der gesprungen werden soll.
Das nimmt man wie gewohnt mal zwei.
Dazu addieren wir dann 6 (Bytes), um das Ende festzulegen.
Das vergleichen wir dann mit der Funktion cp mit ZL, dem LOWbyte.
Das ganze dann nochmal mit dem Highbyte.
Fertig, das ist alles!
Ich verstehs einfach nicht.
Wir haben doch dort eine Schleife, also rufen wir doch auch 6x diesen Befehl hier auf:
ldi temp , LOW ((daten * 2) + daten_laenge)
Wenn nun das Zeichen "!" kommt, dann sind wir ja nicht mehr bei 6 Byte, sondern schon beim 12 Byte.
Hmm..egal ](*,)
Lieber Thomas!
Tust Du mir den gefallen und schaust Du Dir das mal im Simulator an?
Immer mit F11 weiter und beobachte die Register uvm. ...
Hab ich doch schon alles gemacht.
ldi reg1, 0b00000000
ldi reg2, 0b11111111
cp reg2, reg1
Dann hat sich im SREG was geändert, schau ich hier nach: http://www.avr-asm-tutorial.net/avr_...tail.html#SREG
S und N sind auch 1. Was sagt mir das?
Dass das Vorzeichen negativ ist und das Ergebnis dann logischerweise auch negtativ. Was schließe ich daraus? das der Befehl cp reg1 - reg2 rechnet. Aber das ist ja nicht so, denn bei deinem Bild, was du hier eingefügt hast, steht:
cp Rd, Rr Compare Rd - Rr
Müsste dann bei "cp reg2, reg1" wohl reg2 - reg1 sein. Aber da ist das Ergebnis ja nicht negativ, sonder = reg2.
Bei cpc kommt bei den Werte oben dasselbe raus, soweit so gut, doch bei folgenden Werten:
ldi reg1, 0b11111111
ldi reg2, 0b11111111
kommt bei cp reg2, reg1
Z von SREG = 1, also Ergebnis ist 0, also die Werte beider Register sind
gleich, logisch. Aber bei "cpc reg2, reg1" kommt auf einmal nichts raus. Also alle Bits von SREG sind 0. Somit heißt es unter anderem auch, dass die Werte der Register reg1 und reg2 ungleich sind, sind sie aber doch nicht.
Ich hoffe, du weißt nun, wo mein Problem liegt :(
Lieber Thomas! ;o)
Also bei mir funktioniert das richtig!
Ich komme irgendwie mit dem Problem nicht zurecht! ;o9 *schmunzel*
Naja, dann is auch egal, muss ich eben so hinnehmen.
*g* Ist die Funktion trotzdem in etwa klar?
Naja, weniger...
Nach diesem Befehl hierCode:main:
lpm ;Daten laden
mov tmp, lpm_reg ;in temp verschieben
adiw ZL, 1 ;Z um eins erhöhen
ldi tmp, LOW ((daten1 * 2) + daten_laenge) ;vergleiche LOW-Byte
cp ZL, tmp
ldi tmp, HIGH ((daten1 * 2) + daten_laenge) ;vergleiche HIGH-Byte
cpc ZH, tmp
breq ende ;springe zu ende, wenn letztes Byte ausgelesen
rjmp main ;nochmal
ende: ;Endschleif
rjmp ende
mov tmp, lpm_reg
erhöhen wir den Zeiger ja um 1, ne? Damit wir das nächste Byte bekommen, also den nächsten Buchstaben. Und dann benutzt du aber wieder das gleich Register, wo wir ja eigentlich das Wort "Hallo!" drinne haben wollten:
ldi tmp, LOW ((daten1 * 2) + daten_laenge)
Da schreiben wir dann in tmp wieder einen völlig anderen Wert.
[EDIT]
Was mir grad auffällt, nach der Zeile hier:
cp ZL, tmp
da werten wir den Vergleich gar nicht aus, sonder nur nach cpc wird ausgewertet. Wieso das denn? :o
In dem Moment, wo wir die main-Schleife betreten haben wir ja noch die Adresse von 'H' in Z stehen, also daten1 + 0.
Wir lesen dann das 'H' aus.
Danach erhöhen wir auf daten1 + 1 und vergleichen mit dem Wert für das erste Byte nach dem String, also daten1 + 6 (das siebte Byte).
Nun springen wir wieder an den Anfang.
und mache das gleiche mit 'a', 'l', 'l', 'o' und '!'.
Sobald wir nach dem '!' wiederholen, sieht das ganze so aus:
Wir haben im Z daten1 + 5 (6. Byte) und laden mit lpm das Byte in r0.
Das verschieben wir nach temp.
Danach erhöhen wir Z um 1, also haben wir daten1 + 6 (7.Byte, was nciht mehr da ist).
Wir vergleichen nun die Register mit jeweils dem Endwert und da glaich, springen wir mit breq zum Ende!
Ich hoffe es war verständlicher?
Ja, schon ein wenig, zwar nicht ganz...naja, für manche Sachen ist mal wohl zu doof. Das wird auch nicht das wichtigste sein, denk ich. Ich hoffe ich kann auch weitermachen, wenn ich das jetzt hier nicht so richtig verstanden habe.
Aber wenn wir beim "!" angekommen sind, dann ist doch das aktuelle Byte das Byte 6 oder? Weil ja das Ausrufezeichen das 6. Zeichen ist. Und wenn wir dann noch mit daten1+6 vergleichen, dann sind wir ja bei 12, denn 6 (Byte 6 = !) + 6 (Das Ende von der Zeichenkette) = 12.
Hallo Thomas!
Du würfelst jetzt alles durcheinander!
Nur zu Anfang wird die Adresse mal 2 genommen!
Zum Schluss wird immer nur + 1 genommen, ohne dass mal 2 genomnmen wird!
'H' ist das 1. Byte und wird bei (daten1 * 2) + 0 ausgelesen.
'a' ist das 2. Byte und wird bei (daten1 * 2) + 1 ausgelesen.
'l' ist das 3. Byte und wird bei (daten1 * 2) + 2 ausgelesen.
'l' ist das 4. Byte und wird bei (daten1 * 2)1 + 3 ausgelesen.
'o' ist das 5. Byte und wird bei (daten1 * 2) + 4 ausgelesen.
'!' ist das 6. Byte und wird bei (daten1 * 2) + 5 ausgelesen.
FF ist das leere Byte nach dem Strin (Zeichenkette) und wird mit (daten1 * 2) + 6 ausgelesen.
ich glaube ich habe Dich durcheinander gebracht! *lol*
Ich glaub, ich habs nun in etwa verstanden. Ich hab immer gedacht, dass sich daten1 auch verändert. Weil wir ja den Z-Zeiger immer um 1 erhöhen. Also dachte ich, dass sich daten1 erhöht, aber stimmt ja, der Zeiger erhöht sich ja nur, oder? Und das das erhöhen zeigt er auf das nächste Byte, also auf das nächste Zeichen, ne?
Wenn das so stimmt, dann können wir denk ich jetzt weiter machen. Sorry, dass ich uns so aufgehalten hab *g*
Hallo Zusammen,
total interessiert hab ich den kompletten Thread jetzt gelesen! Und habe total Lust darauf bekommen!! Und ich jetzt einsteigen will! Ihr bekommt nen Assembler Mitwohner dazu! Da ich euch net mit blöden Einsteigerfragen belästigen will suche ich ein gutes Tutorial! Kennt ihr ein gutes? Doch eine Frage hab ich jetzt schon: Welches Programm zum programmieren könnt ihr empfehlen?
Gruß Michi
Ich programmiere mit AVR Studio, das ist eigentlich sehr gut. Und das ist hier ein gutes Tutorial ;)
hi,
ist AVRStudio kostenlos? Und mit was proggst du die hex in den Controller? mit ponyprog?
gruß michi
Jo, AVR Studio ist kostenlos. Brennen tu ich mit TwinAVR, da ich mit PonyProg nicht zu meinem Chip conntecten kann.
Gruß
Thomas
hi,
hab gerade gelesen das man ponyprog auch verweden kann! des isch gut weil ich bis jetzt auch mit ponyprog gemacht hab!
gruß michi
Hallo Michael!
Wenn Du alles gelesen hast, dann müsstest Du Sebastains und meine Anfängertipps gelesen haben, wo wir beschrieben haben, wo bzw. wie man anfängt! ;o)
Wilkommen in der ASM-Familie! :o)
Sehr schön! *freu*Zitat:
Ich glaub, ich habs nun in etwa verstanden.
Auf gehts, zu neuen Abenteuern! ;o)
Nein, eben nicht, das sind feste Konstanten, die wir aus dem Flash-Speicher lesen können!Zitat:
Ich hab immer gedacht, dass sich daten1 auch verändert.
Also eine Art Datenbankbibliothek oder Wertetabelle!
Genau, Du hast's geschnallt! *freu* *glückwunsch*Zitat:
Weil wir ja den Z-Zeiger immer um 1 erhöhen. Also dachte ich, dass sich daten1 erhöht, aber stimmt ja, der Zeiger erhöht sich ja nur, oder? Und das das erhöhen zeigt er auf das nächste Byte, also auf das nächste Zeichen, ne?
Kein Problem, dafür heißt das ja jetzt auch Tutorial! ;o)Zitat:
Wenn das so stimmt, dann können wir denk ich jetzt weiter machen. Sorry, dass ich uns so aufgehalten hab *g*
Los gehts! *freu*
Ps:
Ich verwende AVR-Studio (www.atmel.com) und Ponyprog (www.lancos.com), sind beide sehr gut!
*Aufgabe such* :-b *gg*Zitat:
Zitat von Florian
Bitte berechne die Werte für die tongebenden Register für den Kammerton a', c' und c''!
Schaut mal:
https://www.roboternetz.de/phpBB2/statistics.php
*FREU*
Hallo Florian,
welches Programm muss ich hier ruterladen?
Link
Gruß Michi