Wenn 3 da sind und du nimmst 5 weg, mußt du zwei zurücklegen, damit dann kein's mehr da ist ?Zitat:
Zitat von Florian
:mrgreen:
Druckbare Version
Wenn 3 da sind und du nimmst 5 weg, mußt du zwei zurücklegen, damit dann kein's mehr da ist ?Zitat:
Zitat von Florian
:mrgreen:
Hallo Florian,
Ich habe irgendwo den Stack ausführlich behandelt (Hoffe ich),
Nur ich kann mir wirklich gut vorstellen, daß die Leute keine große Lust haben 19 Seiten durchzublättern....
Irgendwas müssen wir uns einfallen lassen, nur was
Gruß Sebastian
@Sebastian: Ganz neu hab ich den Code natürlich nicht geschrieben. Die Standardsaches hab ich übernommen. Ok, hätt natürlich die Kommentare anpassen können ;) Sorry. Dient ja dann auch der Übersichtlichkeit.
Um zur eigentlichen Aufgabe zurück zu kommen. Wir wollten die Tonleiter doch hoch und runter spielen, oder?
Ein Anfänger, so wie ich einer bin, würde jetzt einfach noch die Werte in umgekehrter Reihenfolge ans Ende zu der Datenbank dazuschreiben. Aber das ist sicher nicht das Ziel und auch sicher nicht die eleganteste Lösung. Funktionieren würde es ja, sicher. Aber man muss doch sicher auch irgendwie von hinten anfangen können zum laden, oder wie wollen wir das realisieren?
Gruß
Thomas
[edit]
Hab irgendwie bei meiner Rechtschreibung geschlampt und hiermit verbessert :)
Hmmm, gute Frage, den Stack hatten wir behandelt!
Wir könnten den Thread in Einzelteile zerhacken!
Ihr müsst mir nur sagen, wo ich die Schere ansetzen muss!
Dann hätten wir einen Anfang, Timer, Tonerzeugung, 16 Bit, ...
Was haltet ihr davon?
Dann wirds auch für mich später einfacher daraus ein Tutorial zu schreiben! *lol*
*edit*
@ Thomas:
Dann such aml den umgekehrten Befehl von adiw!
Das ist dann jetzt nur noch ein Katzensprung!
Wenn Du schon selber danach fragst :-)Zitat:
Aber man muss doch sicher auch irgendwie von hinten anfangen können zum laden, oder wie wollen wir das realisieren?
ich sag nur, wir haben bisjetzt adiw benutzt, es gibt aber noch sbiw (wie gut das Atmel
Entwickler sich sowas einfallenlassen haben, oder wer hat den Befehlsatz entwickelt? Intel?)
Recht Dir das?
dann lass jetzt deinen Kopf qualmen.
Gruß Sebastian
@Florian: Ja, aber lass uns das doch später machen, oder?
@Sebastian: Wieso bin ich so dumm wie ich bin? *g*
Ich hab den Befehl sbiw selbst schonmal fälschlicherweiße benutzt, wenn du dich noch erinnern kannst.
Argh, das ärgert mich aber nun *g*
[edit]
Aber da muss ich ja nun wieder eine Hilfsvariable nutzen, die speichert, ob ich schon am Ende war, oder nicht, ne?
Ruhig Blut! *rofl*
Na klar können wir das mit dem Auteilen auch später machen, aber so ist es halt ein Saurier unter Zwergen!
Da traut sich keiner mehr dran!
Ja aber dann würden wir uns Fragen sparen, auf die es schon eine Antwort gibt.Zitat:
@Florian: Ja, aber lass uns das doch später machen, oder?
:lol:Zitat:
@Sebastian: Wieso bin ich so dumm wie ich bin? *g*
Das ist keine einfache Frage!Zitat:
Ihr müsst mir nur sagen, wo ich die Schere ansetzen muss!
Weil, wie soll man sortieren, nach Themen wie z.B Tasten,Blinken,Ton,Musik
Oder lieber nach Themen wie Interrupts, Ports Pins, Stack, Zeiger :-k
Ich glaube, Du liebst Variablen was?Zitat:
Aber da muss ich ja nun wieder eine Hilfsvariable nutzen, die speichert, ob ich schon am Ende war, oder nicht, ne?
Du weißt schon wann Du zuende bist ! oder warum ist Dein Piezo zum schluß stumm ?????
Gruß Sebastian
Ich würd nach Themen wie Interrupts, Ports, Pins usw. sortieren. Darin sind dann Beispiele und dann kann man ja schauen, ob man das Beispiel machen möchte oder nicht.
Ja, ich weiß, wann zuende ist. Aber das Problem ist ja, wenn ich Z um 1 erniedrige, dann erhöht er es ja wieder beim nächsten mal um 1, weil er dann ja wieder nicht am Ende ist.Zitat:
Ich glaube, Du liebst Variablen was?
Du weißt schon wann Du zuende bist ! oder warum ist Dein Piezo zum schluß stumm ?????
Und ja, ich mag Variablen, in denen kann man so viel speichern ;)
Dann leg Dir eine schöne Variable an, wo Du dann speicherst, ob Du rauf oder runter möchtest, und jenachdem machst Du sbiw oder adiw, aber vorsicht, nicht außerhalb der db.
kommen!
achso, und belege nicht einen Register damit, sondern nur ein Bit Du weißt ja sbr cbr damit kannst Du 8 Variablen !!! in einem Register Speichern, cool was ?
Hallo Zusammen,
danke dass ihr soviel Geduld habt!!
Also muss ich immer die Reihenfolge behalten!
Es muss also immer so aussehen oder?:
Speicher Info 1
Speicher Info 2
Speicher Info 3
-----------------------
-----------------------
Lade Info 3
Lade Info 2
Lade Info 1
ich kann aber nicht zuerst die 2 laden! <= stimmt so, oder?
Gruß Michi
Hab grad gemerkt, dass meine geänderte Version von der Tonleiter gar nicht geht. Also die ohne Hilfsvariable. Hab vorhin nämlich das alte nochmal draufgebrannt und nicht gemerkt ](*,)
Wäre nett, wenn du da mal reinschauen könntest:
Er spielt einfach nur den ersten Ton ab (Endlosschleife)Code:;Programm
;CDurTonleiter rauf spielen
.include "m8def.inc"
.def tmp = r16 ;Mein Universallregister
.def tonwert = r17 ;aktueller Wert für den Ton
.def lpm_reg = r0 ;Mein lpm-Register
.equ Summer = PB2 ;Summer an B.2
.equ time0 = 256-255 ;Timer0 für die Tonleiter
.equ time1 = 65536-3600 ;Damit wird der Timer1 vorgeladen, für die Sekunde
.equ daten_laenge = 9 ;Anzahl der Werte
.org 0x000
rjmp reset ;Interruptvektor "reset:"
.org OVF1addr
rjmp pruefSek ;Interruptvektor "pruefSek:"
.org OVF0addr
rjmp timerSummer ;Interruptvektor "timerSummer:"
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
;Timer Register für Ton werden belegt, hier Timer 0
ldi tmp, (1<<CS02) ;Prescaler ist 256
out TCCR0, tmp ;Register TCCR0 ist für den Prescaller zuständig
ldi tmp, time0 ;Hier wird der Timer vorgeladen
out TCNT0, tmp
;Timer Register für Sekunde werden belegt, hier Timer 1
ldi tmp, (1<<CS12) | (1<<CS10) ;Prescaler ist 1024
out TCCR1B, tmp
ldi tmp, HIGH(time1) ;Für den Timer1 (16Bit) benötigen
out TCNT1H, tmp ;wir 2 Register, in denen wir den Wert
ldi tmp, LOW(time1) ;für die 1 Sekunde (10000) speichern ->
out TCNT1L, tmp ;"TCNT1H" und TCNT2L"
ldi tmp, (1<<TOIE0) | (1<<TOIE1);Hier werden Interrupts nach Timer0 Überlauf eingeschaltet
out TIMSK, tmp ;Register TIMSK ist dafür zuständig
;Z-Register mit DB "tonleiter1" füllen
ldi ZH, HIGH(tonleiter1 * 2)
ldi ZL, LOW(tonleiter1 * 2)
sbi DDRB, Summer ;B.2 als Ausgang
sbi PORTB, Summer ;B.2 auf HIGH stellen
sei ;Interrupts zulassen
;Die Hauptschleife, die sich immer wiederholt und den Tonwert neu einliest
main:
lpm ;Daten von tonleiter1: holen
mov tonwert, lpm_reg ;Wrt von lpm_reg in tonwert speichern
rjmp main ;immer wieder zurück zu main springen
;Läuft Timer1 über, so wird erstmal geprüft, ob der letzte Ton
;erreicht ist und der Timer1 wird neu vorgeladen
pruefSek:
push tmp ;tmp sichern
in tmp, SREG
push tmp ;SREG sichern
rjmp tonPruefen ;springe zu "tonPruefen"
ldi tmp, HIGH(time1) ;Für den Timer1 (16Bit) benötigen
out TCNT1H, tmp ;wir 2 Register, in denen wir den Wert
ldi tmp, LOW(time1) ;für die 1 Sekunde (10000) speichern ->
out TCNT1L, tmp ;"TCNT1H" und TCNT2L"
pop tmp
out SREG, tmp ;SREG wiederholen
pop tmp ;tmp wiederholen
reti ;Spring wieder dahin, wo du hergekommen bist
;Hier wird Z-Zeiger um 1 erhöht. Es wird hier auch verglichen,
;ob der letzte Ton erreicht, wenn ja, dann springt er zu "endeTon"
tonPruefen:
lpm ;Daten von tonleiter1: holen
adiw ZL,1 ;Z um 1 erhöhen, nächstes Byte
ldi tmp, LOW ((tonleiter1 * 2) + daten_laenge) ;vergleiche LOW-Byte
cp ZL, tmp
ldi tmp, HIGH ((tonleiter1 * 2) + daten_laenge) ;vergleiche HIGH-Byte
cpc ZH, tmp
breq endeTon ;springe zu "endeTon:", wenn letztes Byte ausgelesen
ret ;zurück, wo du hergekommen bist
;Hier wird der Timer gestoppt, indem wir den Prescaler auf 0 setzen
endeTon:
ldi tmp, (0<<CS02) ;Timer stoppen
out TCCR0, tmp
ret ;zurück wo du hergekommen bist
;Läuft Timer0 über, so wird B.2 umgeschaltet, sodass Ton
;aus dem Summer zu hören ist
timerSummer:
push tmp ;tmp sichern
in tmp, SREG
push tmp ;SREG sichern
sbis PINB, Summer ;ist B.2 = 1?
rjmp timerSummer1 ;NEIN -> spring zu "timerSummer1:"
cbi PORTB, Summer ;JA -> setze B.2 auf 0
rjmp timerSummer2 ;springe zu "timerSummer2:"
timerSummer1:
sbi PORTB, Summer ;B.2 auf 1 setzen
timerSummer2:
pop tmp ;SREG wiederholen
out SREG, tmp
pop tmp ;tmp wiederholen
reti
;Das sind die Werte, womit der Timer0 (Tonleiter-Timer) vorgeladen wird
tonleiter1:
.db 256-55, 256-49, 256-44, 256-41 ;Wert zum Vorladen für den Timer
.db 256-37, 256-33, 256-29, 256-27, 0 ;für die Tonleiter
@Michi: Genau so muss das aussehen! Richtig.
Genau, daß habe ich irgendwo oben schon geschrieben, stell Dir vor Du hast einen Gabelstapler, der nur eine Palette aufnehmen kann, du mußt also immer die oberste abnehmen, zwei auf einmal geht nicht, und dazwischen geht auch nicht, immer einen drauf oder einen runter.Zitat:
ich kann aber nicht zuerst die 2 laden! <= stimmt so, oder?
Ich wollte vorhin schon was sagen, ich glaube Timer0 wird nicht mehr geladen, kann das?Zitat:
Wäre nett, wenn du da mal reinschauen könntest:
Ja, das war der Fehler, allerdings muss sich da noch irgendwo ein Fehler eingeschlichen haben, denn er spielt zwar jetzt nen anderen Ton, aber dann auch nur den. Und jede Sekunde kommt ein kurzer Stocker. Dann spielt er aber weiter den gleichen Ton, wieder für eine Sekunde.
Hab schon überprüft, also richtig hochzählen müsst er ja, also nach 1 Sekunde immer den nächsten Wert holen. Komisch...Code:;Programm
;CDurTonleiter rauf spielen
.include "m8def.inc"
.def tmp = r16 ;Mein Universallregister
.def tonwert = r17 ;aktueller Wert für den Ton
.def lpm_reg = r0 ;Mein lpm-Register
.equ Summer = PB2 ;Summer an B.2
.equ time0 = 256-255 ;Timer0 für die Tonleiter
.equ time1 = 65536-3600 ;Damit wird der Timer1 vorgeladen, für die Sekunde
.equ daten_laenge = 9 ;Anzahl der Werte
.org 0x000
rjmp reset ;Interruptvektor "reset:"
.org OVF1addr
rjmp pruefSek ;Interruptvektor "pruefSek:"
.org OVF0addr
rjmp timerSummer ;Interruptvektor "timerSummer:"
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
;Timer Register für Ton werden belegt, hier Timer 0
ldi tmp, (1<<CS02) ;Prescaler ist 256
out TCCR0, tmp ;Register TCCR0 ist für den Prescaller zuständig
ldi tmp, time0 ;Hier wird der Timer vorgeladen
out TCNT0, tmp
;Timer Register für Sekunde werden belegt, hier Timer 1
ldi tmp, (1<<CS12) | (1<<CS10) ;Prescaler ist 1024
out TCCR1B, tmp
ldi tmp, HIGH(time1) ;Für den Timer1 (16Bit) benötigen
out TCNT1H, tmp ;wir 2 Register, in denen wir den Wert
ldi tmp, LOW(time1) ;für die 1 Sekunde (10000) speichern ->
out TCNT1L, tmp ;"TCNT1H" und TCNT2L"
ldi tmp, (1<<TOIE0) | (1<<TOIE1);Hier werden Interrupts nach Timer0 Überlauf eingeschaltet
out TIMSK, tmp ;Register TIMSK ist dafür zuständig
;Z-Register mit DB "tonleiter1" füllen
ldi ZH, HIGH(tonleiter1 * 2)
ldi ZL, LOW(tonleiter1 * 2)
sbi DDRB, Summer ;B.2 als Ausgang
sbi PORTB, Summer ;B.2 auf HIGH stellen
sei ;Interrupts zulassen
;Die Hauptschleife, die sich immer wiederholt und den Tonwert neu einliest
main:
lpm ;Daten von tonleiter1: holen
mov tonwert, lpm_reg ;Wrt von lpm_reg in tonwert speichern
rjmp main ;immer wieder zurück zu main springen
;Läuft Timer1 über, so wird erstmal geprüft, ob der letzte Ton
;erreicht ist und der Timer1 wird neu vorgeladen
pruefSek:
push tmp ;tmp sichern
in tmp, SREG
push tmp ;SREG sichern
rjmp tonPruefen ;springe zu "tonPruefen"
ldi tmp, HIGH(time1) ;Für den Timer1 (16Bit) benötigen
out TCNT1H, tmp ;wir 2 Register, in denen wir den Wert
ldi tmp, LOW(time1) ;für die 1 Sekunde (10000) speichern ->
out TCNT1L, tmp ;"TCNT1H" und TCNT2L"
pop tmp
out SREG, tmp ;SREG wiederholen
pop tmp ;tmp wiederholen
reti ;Spring wieder dahin, wo du hergekommen bist
;Hier wird Z-Zeiger um 1 erhöht. Es wird hier auch verglichen,
;ob der letzte Ton erreicht, wenn ja, dann springt er zu "endeTon"
tonPruefen:
lpm ;Daten von tonleiter1: holen
adiw ZL,1 ;Z um 1 erhöhen, nächstes Byte
ldi tmp, LOW ((tonleiter1 * 2) + daten_laenge) ;vergleiche LOW-Byte
cp ZL, tmp
ldi tmp, HIGH ((tonleiter1 * 2) + daten_laenge) ;vergleiche HIGH-Byte
cpc ZH, tmp
breq endeTon ;springe zu "endeTon:", wenn letztes Byte ausgelesen
ret ;zurück, wo du hergekommen bist
;Hier wird der Timer gestoppt, indem wir den Prescaler auf 0 setzen
endeTon:
ldi tmp, (0<<CS02) ;Timer stoppen
out TCCR0, tmp
ret ;zurück wo du hergekommen bist
;Läuft Timer0 über, so wird B.2 umgeschaltet, sodass Ton
;aus dem Summer zu hören ist
timerSummer:
push tmp ;tmp sichern
in tmp, SREG
push tmp ;SREG sichern
sbis PINB, Summer ;ist B.2 = 1?
rjmp timerSummer1 ;NEIN -> spring zu "timerSummer1:"
cbi PORTB, Summer ;JA -> setze B.2 auf 0
rjmp timerSummer2 ;springe zu "timerSummer2:"
timerSummer1:
sbi PORTB, Summer ;B.2 auf 1 setzen
timerSummer2:
out TCNT0, tonwert ;Timer0 neu vorladen
pop tmp ;SREG wiederholen
out SREG, tmp
pop tmp ;tmp wiederholen
reti
;Das sind die Werte, womit der Timer0 (Tonleiter-Timer) vorgeladen wird
tonleiter1:
.db 256-55, 256-49, 256-44, 256-41 ;Wert zum Vorladen für den Timer
.db 256-37, 256-33, 256-29, 256-27, 0 ;für die Tonleiter
Ahh, es gibt Probleme mit dem Befehll "ret", irgendwann ruft er dann wieder "reset:" auf, hmm..mal schaun, wie ich das löse :o
Das alles sieht echt nicht gut aus:Zitat:
pruefSek:
push tmp ;tmp sichern
in tmp, SREG
push tmp ;SREG sichern
rjmp tonPruefen ;springe zu "tonPruefen"
ldi tmp, HIGH(time1) ;Für den Timer1 (16Bit) benötigen
out TCNT1H, tmp ;wir 2 Register, in denen wir den Wert
ldi tmp, LOW(time1) ;für die 1 Sekunde (10000) speichern ->
out TCNT1L, tmp ;"TCNT1H" und TCNT2L"
pop tmp
out SREG, tmp ;SREG wiederholen
pop tmp ;tmp wiederholen
reti ;Spring wieder dahin, wo du hergekommen bist
;Hier wird Z-Zeiger um 1 erhöht. Es wird hier auch verglichen,
;ob der letzte Ton erreicht, wenn ja, dann springt er zu "endeTon"
tonPruefen:
lpm ;Daten von tonleiter1: holen
adiw ZL,1 ;Z um 1 erhöhen, nächstes Byte
ldi tmp, LOW ((tonleiter1 * 2) + daten_laenge) ;vergleiche LOW-Byte
cp ZL, tmp
ldi tmp, HIGH ((tonleiter1 * 2) + daten_laenge) ;vergleiche HIGH-Byte
cpc ZH, tmp
breq endeTon ;springe zu "endeTon:", wenn letztes Byte ausgelesen
ret ;zurück, wo du hergekommen bist
;Hier wird der Timer gestoppt, indem wir den Prescaler auf 0 setzen
endeTon:
ldi tmp, (0<<CS02) ;Timer stoppen
out TCCR0, tmp
ret ;zurück wo du hergekommen bist
1. Verlasse nie die Interruptroutine(außer mit reti), es sei denn es geht wirklich nicht anders!
bezogen auf rjmp tonpruefen
muß das sein? warum springst Du dahin? wäre es nicht einfacher das alles direkt
drunter zu schreiben?
2. Mal angenommen, es müßte wirklich so gelöst werden, was sollen die ret's darunter?
bist Du Dir in klarem, wo er hinspringt, wenn da ein ret steht, und vorallem was danach passiert ?
P.S. Jetzt nicht traurig werden, aber das ist Deine häufige Fehlerquelle !
Mit dem ret wollte ich bezwecken, dass er wieder dahin springt, wo er hergekommen ist. Also in dem Falle hier:
Springt er beim ersten ret wieder in die Zeile hier:Code:pruefSek:
push tmp ;tmp sichern
in tmp, SREG
push tmp ;SREG sichern
rjmp tonPruefen ;springe zu "tonPruefen"
ldi tmp, HIGH(time1) ;Für den Timer1 (16Bit) benötigen
out TCNT1H, tmp ;wir 2 Register, in denen wir den Wert
ldi tmp, LOW(time1) ;für die 1 Sekunde (10000) speichern ->
out TCNT1L, tmp ;"TCNT1H" und TCNT2L"
pop tmp
out SREG, tmp ;SREG wiederholen
pop tmp ;tmp wiederholen
reti ;Spring wieder dahin, wo du hergekommen bist
;Hier wird Z-Zeiger um 1 erhöht. Es wird hier auch verglichen,
;ob der letzte Ton erreicht, wenn ja, dann springt er zu "endeTon"
tonPruefen:
lpm ;Daten von tonleiter1: holen
adiw ZL,1 ;Z um 1 erhöhen, nächstes Byte
ldi tmp, LOW ((tonleiter1 * 2) + daten_laenge) ;vergleiche LOW-Byte
cp ZL, tmp
ldi tmp, HIGH ((tonleiter1 * 2) + daten_laenge) ;vergleiche HIGH-Byte
cpc ZH, tmp
breq endeTon ;springe zu "endeTon:", wenn letztes Byte ausgelesen
ret ;zurück, wo du hergekommen bist
;Hier wird der Timer gestoppt, indem wir den Prescaler auf 0 setzen
endeTon:
ldi tmp, (0<<CS02) ;Timer stoppen
out TCCR0, tmp
ret ;zurück wo du hergekommen bist
ldi tmp, HIGH(time1) ;Für den Timer1 (16Bit) benötigen
also 1 unter dem rjmp-Befehl, wo er ja vorher weggesprungen ist.
PS: Traurig bin ich nicht, will nur nicht, dass du böse bist *g* Weiß ja nicht, wie du die Hände übern Kopf zusammenschlägst und dir denkst "Wie kann man nur so blöd sein" ;)
Na ja jetzt übertreibst Du aber.Zitat:
denkst "Wie kann man nur so blöd sein"
aber mit ret hollt der sich zwei Bytes vom Stack und versucht zu dieser Adresse hinzuspringen....
und was liegt ganz oben auf dem Stack?
Abbild von SREG und darunter abbild von tmp #-o
Welche Rücksprungadresse errechnet er sich wohl daraus ?
Lass das mit dem ret sein, versuche lieber tonPruefen: und ende_ton: in die Routine mit reinzunehmen (über reti) und springe da nicht so einfach hin, wozu (ich sehe du hast in C Programmiert bis jetzt hä?)
Gruß Sebastian
Ja, hab vorher in C, genauer gesagt in C++ programmiert.
Also muss ich das dann so machen? Denn eine Sprungmarke brauch ich ja, damit ich den Timer dann abstelle, wenn er das Ende erreicht hat, oder?
Doch dann hab ich ja 3 Zeilen doppelt. Die 3 Zeilen zum Wiederholen der Register vom Stack. Ist also auch nicht die beste Möglichkeit.Code:pruefSek:
push tmp ;tmp sichern
in tmp, SREG
push tmp ;SREG sichern
ldi tmp, HIGH(time1) ;Für den Timer1 (16Bit) benötigen
out TCNT1H, tmp ;wir 2 Register, in denen wir den Wert
ldi tmp, LOW(time1) ;für die 1 Sekunde speichern ->
out TCNT1L, tmp ;"TCNT1H" und TCNT2L"
lpm ;Daten von tonleiter1: holen
adiw ZL,1 ;Z um 1 erhöhen, nächstes Byte
ldi tmp, LOW ((tonleiter1 * 2) + daten_laenge) ;vergleiche LOW-Byte
cp ZL, tmp
ldi tmp, HIGH ((tonleiter1 * 2) + daten_laenge) ;vergleiche HIGH-Byte
cpc ZH, tmp
breq endeTon ;springe zu "endeTon:", wenn letztes Byte ausgelesen
pop tmp
out SREG, tmp ;SREG wiederholen
pop tmp ;tmp wiederholen
reti ;Spring wieder dahin, wo du hergekommen bist
endeTon:
ldi tmp, (0<<CS02) ;Timer stoppen
out TCCR0, tmp
pop tmp
out SREG, tmp ;SREG wiederholen
pop tmp ;tmp wiederholen
reti
und zweimal reti, das hatten wir schonmal, oder?
Logisch denken muß man hier, wenn Du in C/C++ mißt programmierst, merkt das der Compiler meistens und haut Dir auf die Finger, der Assembler macht das nicht.
schau Du benutzt breq endeton,
nimm doch einfach brne irgendwas:
darunter schreibst Du die Befehle um den Timer anzuhalten
dann das label irgendwas:
und hier den Ausklang , verstanden?
Also so?
Fällt mir noch ein wenig schwer, so zu denken, aber ich werds denk ich noch hinbekommen.Code:pruefSek:
push tmp ;tmp sichern
in tmp, SREG
push tmp ;SREG sichern
ldi tmp, HIGH(time1) ;Für den Timer1 (16Bit) benötigen
out TCNT1H, tmp ;wir 2 Register, in denen wir den Wert
ldi tmp, LOW(time1) ;für die 1 Sekunde speichern ->
out TCNT1L, tmp ;"TCNT1H" und TCNT2L"
lpm ;Daten von tonleiter1: holen
adiw ZL,1 ;Z um 1 erhöhen, nächstes Byte
ldi tmp, LOW ((tonleiter1 * 2) + daten_laenge) ;vergleiche LOW-Byte
cp ZL, tmp
ldi tmp, HIGH ((tonleiter1 * 2) + daten_laenge) ;vergleiche HIGH-Byte
cpc ZH, tmp
brne regwiederholen ;Ist Ende erreicht?
ldi tmp, (0<<CS02) ;JA -> Timer0 abstellen
out TCCR0, tmp
regwiederholen:
pop tmp
out SREG, tmp ;SREG wiederholen
pop tmp ;tmp wiederholen
reti
Mal so nebenbei, beim compilieren bringt er mir folgendes Warnung:
Wenn ich die 0 hinten bei meiner DB rausnehmen, ist die Warnung weg. Soll ich die Warnung einfach ignorieren, oder wann kommt es dann zu Fehlern?Zitat:
warning: .cseg .db misalignment - padding zero byte
Der Florian wat Euch das schon gesagt, die Anzahl der Bytes in .db muß GERADE sein
Der Speicher ist in Worten (2 Bytes) organisiert, und wenn Du eine ungerade Zahl hast hängt er eine 0 hinter und meckert, also noch eine null hintern dran, oder wenn eh nicht erforderlich die null wegmachen.
Klappt das jetzt ?
Axo, daher weht der Wind. Ok, danke.
Werd jetzt versuchen, das wieder rückwärts abzuspielen, aber ohne Hilfsvariable, denn wenn du sagst, dass es auch ohne geht, dann muss es ja auch ohne gehen.
Mal schaun *kopf anstreng*
Hmm..irgendwas stimmt da noch nicht...Er läuft wie gehabt bis zum Ende durch, dann soll er aber wieder zurück laufen, also subtrahiere ich wieder 1. Aber beim nächsten Durchlauf addiert er ja wieder 1 und wir sind wieder beim letzten Ton. Also dacht ich mir, subtrahiere ich einfach 2. Dann liest er, sobald er den letzten Ton erreicht hat, bei der nächsten Sekunde den vorletzten Ton aus (klingt gut). Aber bei der nächsten Sekunde sagt er dann wieder, dass er noch nicht am Ende ist, stimmt ja auch, weil er beim vorletzten Ton wieder ist und nicht beim letzten.
Lange Rede, kurzer Sinn, hier mal der Code:
Weiß nicht, ob ich überhaupt mit 2 subtrahieren muss oder ob es da eine ganz andere Möglichkeit gibt. Denn ich möcht das nun gerne ohne Hilfsvariable schaffen.Code:pruefSek:
push tmp ;tmp sichern
in tmp, SREG
push tmp ;SREG sichern
ldi tmp, HIGH(time1) ;Für den Timer1 (16Bit) benötigen
out TCNT1H, tmp ;wir 2 Register, in denen wir den Wert
ldi tmp, LOW(time1) ;für die 1 Sekunde speichern ->
out TCNT1L, tmp ;"TCNT1H" und TCNT2L"
lpm ;Daten von tonleiter1: holen
adiw ZL,1 ;Z um 1 erhöhen, nächstes Byte
ldi tmp, LOW ((tonleiter1 * 2) + daten_laenge) ;vergleiche LOW-Byte
cp ZL, tmp
ldi tmp, HIGH ((tonleiter1 * 2) + daten_laenge) ;vergleiche HIGH-Byte
cpc ZH, tmp
brne regwiederholen ;Ist Ende erreicht?
;JA -> wieder zurückzählen
lpm ;Daten von tonleiter1: holen
sbiw ZL,2 ;Z um 2 erniedrigen, vorheriges Byte
ldi tmp, LOW ((tonleiter1 * 2) + daten_laenge) ;vergleiche LOW-Byte
cp ZL, tmp
brne regwiederholen ;Ist Anfang erreicht?
ldi tmp, (0<<CS02) ;JA -> Timer0 abstellen
out TCCR0, tmp
regwiederholen:
pop tmp
out SREG, tmp ;SREG wiederholen
pop tmp ;tmp wiederholen
reti
O weh Thomas,
ich glaube da habe ich etwas zu schnell gesagt :frown:
Du hast recht, man müßte sich irgendwie merken, ob man rauf oder runter will :frown:
Ich habe Dich durcheinander gebracht mach Dir wirklich eine schöne Variable :frown:
:cry: :cry: :cry:
Hmm...bin kurz davor, dass es geht, aber irgendwie will es noch nicht. Teste die ganze Zeit im Simulator. Er macht aber nie den Timer aus, also er springt nie da rein, wo er den Timer0 abestellen soll.
Er müsste aber eigentlich reinspringen, denn irgendwann ist doch ZL wieder auf 0, oder?Code:pruefSek:
push tmp ;tmp sichern
in tmp, SREG
push tmp ;SREG sichern
ldi tmp, HIGH(time1) ;Für den Timer1 (16Bit) benötigen
out TCNT1H, tmp ;wir 2 Register, in denen wir den Wert
ldi tmp, LOW(time1) ;für die 1 Sekunde speichern ->
out TCNT1L, tmp ;"TCNT1H" und TCNT2L"
lpm ;Daten von tonleiter1: holen
sbrc tonleiterEnde, 0 ;Ist tonleiterEnde = 0?
rjmp subtrahiereZ ;Wenn tonleiter = 1, dann subtrahiere Z um 1
addiereZ:
adiw ZL, 1 ;Z um 1 erhöhen
rjmp pruefSek2 ;zu "pruefSek2:" springen
subtrahiereZ:
sbiw ZL, 1 ;Z um 1 erniedrigen
pruefSek2:
ldi tmp, LOW ((tonleiter1 * 2) + daten_laenge) ;vergleiche LOW-Byte
cp ZL, tmp
ldi tmp, HIGH ((tonleiter1 * 2) + daten_laenge) ;vergleiche HIGH-Byte
cpc ZH, tmp
brne pruefTonaus ;zu "pruefTonaus:" springen
sbr tonleiterEnde, 1 ;Hilfsvariable.1 auf 1 setzen
pruefTonaus:
cp ZL, tmp ;Ist Anfang erreicht?
brne regwiederholen
ldi tmp, (0<<CS02) ;JA -> Timer0 abstellen
out TCCR0, tmp
regwiederholen:
pop tmp
out SREG, tmp ;SREG wiederholen
pop tmp ;tmp wiederholen
reti
naja , der Ansatz ist schon ok, ABER
schau da
pruefTonaus:
cp ZL,tmp
was wird da Verglichen?
welchen Wert has tmp? vielleicht HIGH((tonleiter1 * 2) + daten_laenge)
Du Vergleichst Äpfel mit Birnen ! :-)
1. Dieser Gespann cp cpc müßte da auch hin.
2. Du müßtest eigentlich mit (tonleiter1 * 2) vergleichen weil Du Dich wieder nach vorne Bewegt hast, oder sehe ich das falch ? :-k
Äpfel mit Birnen ist nicht gut ;)
Hmm...nu hab ich dieses Label so:
Aber dann spielt er nur den ersten Ton ab und dann ist Schluss.Code:pruefTonaus: ;Ist Anfang erreicht?
ldi tmp, LOW ((tonleiter1 * 2) + daten_laenge) ;vergleiche LOW-Byte
cp ZL, tmp
breq regwiederholen
ldi tmp, (0<<CS02) ;JA -> Timer0 abstellen
out TCCR0, tmp
Das "HIGHT-Byte" interessiert mich doch zu dem Zeitpunkt gar nicht mehr, oder?
wie kommst Du darauf ?Zitat:
Das "HIGHT-Byte" interessiert mich doch zu dem Zeitpunkt gar nicht mehr, oder?
Stell Dir mal vor wir hätten so ein 2 Bytes gespann:
High 11000111 Low 00000000
was passiert , wenn ich jetzt sbiw benutze ?
wie sehen die Bytes aus ?
ich wiederhole mich :
Du müßtest eigentlich mit (tonleiter1 * 2) vergleichen weil Du Dich wieder nach vorne Bewegt hast, oder sehe ich das falch ? Think
Ahjo, vergleichen mit (tonleiter * 2) geht das so alleine erstmal nicht, wahrscheinlich auch logisch.
Das ist ja eben mein Problem. Florian konnte mir das leider nicht erklären.Zitat:
Stell Dir mal vor wir hätten so ein 2 Bytes gespann:
High 11000111 Low 00000000
was passiert , wenn ich jetzt sbiw benutze ?
wie sehen die Bytes aus ?
Also wenn jetzt sbiw benutzt wird..hmm...kommt drauf an, wo der Z-Zeiger grad ist, oder? Der liest doch immer 2 Bits aus, ne? Hmm..sorry, keine Ahnung, ich kapiers nicht.
Warum soll er 2 Bytes rauslesen?
Pass auf
daten:
.db 10,20,30,40,50,60
ldi ZH,HIGH(daten * 2 )
ldi ZL,LOW(daten * 2 )
Der Z Zeiger zeigt auf den ersten Byte bei daten,
wenn ich jetzt lpm mache erhalte ich eine 10 in den R0
adiw ZL,1 , der Zeiger zeigt auf die 20
nochmal adiw ZL,1 der Zeiger zeigt auf die 30
jetzt mal adiw ZL,2 der Zeiger zeigt auf die 50
sbiw ZL,1 der Zeiger Zeigt auf die 40
sbiw ZL,1 der Zeiger Zeigt auf die 30
ldi ZH,HIGH(daten * 2 )
ldi ZL,LOW(daten * 2 ) er zeigt wieder auf die 10
Dieses mal 2 kommt davon daß der Speicher Wortweise (2 Bytes) organisiert ist
Nimm das einfach so hin, merke Dir nur daß da immer * 2 hinkommt
Vielleicht findet sich hier jemand der das einfacher erklären kann,
ich kann es nicht :-(
Ok, und das HIGH und LOW kommt dadurch, weil wir hier mit 16Bit arbeiten, richtig?
Und wieso muss ich LOW mit cp vergleichen und HIGH mit cpc? Hab mir das ja auch schon alles im Simulator angeschaut und gesehen, wie sich das auch im SREG ändert, aber bin leider nicht dahinter gestiegen.
Also cp ist wie Du schon irgendwomal geschrieben hast in der Tat Subtrahieren, mit dem Unterschied daß die Inhalte unverändert bleiben, nur die Bits Im SREG Register entsprechend dem Ergebnis gesetzt werden.
Wie Vergleicht man in der Mathe 2 Zahlen ??
Wenn wir draufschauen und zwei Zahlen sehen, dann können wir sagen daß 10 gleich 10 ist oder 10 kleiner als 20 ist.
Aber woher soll der AVR das wissen?
Er kann nur eine Zahl von der anderen abziehen, und anhand des SREG exakt sagen welche kleiner größer oder halt ob beide gleich sind!
Nehmen wir als Beispiel zwei gleiche Zahlen
100 und 100
wenn du jetzt sie in zwei register lädst und mit cp "behandelst"
Verändern sie sich nicht, nur im SREG wird das Z Bit gesetzt
was heißt daß das ergebnis 0 ist (klar 100 -100 = 0) :-)
so, wenn jetzt danach z.B. der befehl breq kommt schaut er nach ob Z Bit im SREG 0 oder 1 ist wenn 1 springt er, wenn 0 nicht das war doch einfach oder,
so gleich machen wir des mit 16 Bit und cpc *schüttel*
Du kannst auch die Zwei Zahlen mit verschiedenen Werten laden, und schauen wie sich die Bits im SREG verändern (ganz interresant sind Vorzeichen, Negativ und Übertragsflags
Bis dahin hab ichs erstmal verstanden.
Den Übertragsflag versteh ich nicht ganz. Ist das denn der Übertrag, den man auch aus dem schriftlichen rechnen kennt?
[edit]
Also nehmen wir mal die Zeilen hier:
Nach der Zeile "cp ZL, tmp" wird doch gar nicht mit breq oder brne geprüft, wie das Ergebnis war, wozu vergleicht man dann eigentlich? :-kCode:ldi tmp, LOW ((tonleiter1 * 2) + daten_laenge) ;vergleiche LOW-Byte
cp ZL, tmp
ldi tmp, HIGH ((tonleiter1 * 2) + daten_laenge) ;vergleiche HIGH-Byte
cpc ZH, tmp
brne pruefTonaus ;zu "pruefTonaus:" springen
Du hast es erkannt!
jetzt machen wir knüppeldick....
machen wir jetzt 2 16 Bit Zahlen (naja eigentlich 10 aber wir brauchen jetzt 16 Bit um sie zu speichern)
erste Zahl 1000 zweite Zahl 1001
die passen ja nicht in 8 Bit rein :-(
also werden sie zerschlagen in High Byte und Low Byte tipe mal in Deinem Taschenrechner 1000 ein und wandle es in binär um, was kommt dabei raus ?
1111101000 also werden sie so aufgeteilt High -> 00000011 Low -> 11101000
und 1001 ?
11111010001 High -> 00000011 Low->11101001
und da wir Menschen sind und dezimale schreibweise voll geil finden wandeln wir uns das um ,
die beiden Highs ergeben 3 juhu gleich!
und Lows 232 und 233 naja da ist nix meh gleich :-(
so jetzt rechnen!
cp 232,233 -> schaue was sich im SREG getan hat Vorzeichen, Halbübertrag,Negativ und Übertrag sind gesetzt,
bis auf den Halbübertrag ist wohl klar oder?
Bei Halbübertrag muß ich auch passen, was der zu sagen hat habe ich bis jetzt noch nicht raus :-( vielleicht weiß der Florian das, oder sonst jemand
aber die anderen Flags sind wohl klar oder ?
Jetzt müssen wir noch die zwei Highs vergleichen, könnten ja auch anders sein, ABER
wir müssen den Übertrag(auch Carry) mit in die Rechnung nehmen (wie Du schon sagtest schriftliches rechnen)
und dazu ist der Befehl cpc (cp mit Carry)
also 3,3 wäre eigentlich ja gleich, dann wäre nur Z SREG 1, aber da wir noch den Carry (der ja 1 ist) mit abziehen, haben wir ja, naja schau selber im Sim
ich hoffe daß es jetzt doch etwas einfacher ist.
Das bezieht sich auch auf add und adc! Genau dasselbe nur halt addieren
P.S. Genauso wird auch mit Zahlen, die 24 32 und mehr Bytes haben verfahren...
Ich weiß daß es schwer ist aber leider leider (man denke da an c if a>10000 ....)
Aber Du wolltest ja selber auf der Hardwareebene programmieren :-) :-)
Edit:nach cp nicht aber nach cpc, ich hoffe daß jetz alles klar ist [-o<Zitat:
Nach der Zeile "cp ZL, tmp" wird doch gar nicht mit breq oder brne geprüft, wie das Ergebnis war, wozu vergleicht man dann eigentlich? Think
Hallo ihr Eifrigen!
Entschuldigt bitte, dass ich mich ein Wenig aus diesem Thread zurückgezogen habe, ich muss noch einiges Wichtiges erledigen und habe kaum Zeit hier mitzulesen!
Seit mir bitte nicht böse! *hoff*
Schaffst Du das auch ohne mich Sebastian? *dumme Frage, Du hast es ja sowieso fast hauptsächlich gemacht -> g*
Hallo Florian , ich hoffe es [-o<
wir stoßen jetzt auf Sachen , die wirklich sauschwer für uns Menschen sind,
aber ich hoffe, daß [-o<
Aber um unser Werk zu vollenden werden wir Dich ja noch brauchen :-)
Du kennst Ja unser Ziel in dieser Übung :-)
Nette Erklärung, danke :)
Es ist schon ein wenig klarer geworden, aber ich versteh immer noch nicht, wie ich herrausfinde, wann ich cp und wann ich cpc nehmen muss.
Wenn ich zwei gleiche Zahlen habe und diese mit cpc vergleiche, dann sind alle Flags im SREG auf 0, also keines ist gesetzt.
Ja wie ? immer bei Zahlen die 8 bit haben cpZitat:
aber ich versteh immer noch nicht, wie ich herrausfinde, wann ich cp und wann ich cpc nehmen muss.
und bei zahlen die 16 und mehr die lows mit cp und den ganzen rest (meistens nur Highs)
cpc
genauso addieren mache mal sim und addiere mal zwei 16 bit zahlen,
das ist einfacher zu verstehen wenn ergebnis von add also beide lows höher als 255 ist
wir carry gesetzt und bei den highs machst Du adc also beide hight und den carry dabei
(wie normales rechnen auf papier, wenn ergebnis höcher 9 wird eine 1 mit eine Zeile weiter mitgenommen die 1 ist halt auch carry)
also bei lows cp sub oder add
bei highs cpc sbc oder adc
klar?