Hi,
ich hab's jetzt kapiert! Der Timer wird mit 1 vorgeladen damit er schon nach 254 Timerschritten nen Interrupt auslöst! <= ist das so oder? Sonst löst er doch nach 255 einen aus, oder?
Gruß Michi
Hi,
ich hab's jetzt kapiert! Der Timer wird mit 1 vorgeladen damit er schon nach 254 Timerschritten nen Interrupt auslöst! <= ist das so oder? Sonst löst er doch nach 255 einen aus, oder?
Gruß Michi
Er löst nach 256 den Interrupt erst aus, da er bei 255 noch nicht überläuft, deswegen ja auch die 256 (so, nun hast die Erklärung)
Und wenn du schreibst: 256-255, dann lädst du den Timer also mit 1 vor. Also läuft er nach 255 Schritten über und löst den Interrupt aus.
@Sebastian:
.equ time 65536-3600
Denn
1/3,6864 MHz = 271ns
271ns * 1024 = 278µs
278µs * 3600 = 1000,8 ms
Wunderbar![]()
@Thomas, klappt es jetzt mit dem Timer1 ?
Ich meine Dein Musikprogramm?
@Tekeli,
Danke für den Tip mit VMware, aber ich glaube daß Programm unterliegt nicht der GPL
und Du kannst mich für bekloppt erklären, bei mit kommt nur opensource drauf
Gruß Sebastian
@Sebastian:
Jo, klappt nun mit dem Timer1. Allerdings brauche ich immer noch eine Hilfsvariable, die ich beim Überlauf von Timer1 auf 255 setze und dann in der main prüfe und dementsprechend dann den nächsten Ton lade. Hier nochmal der Code:
Weiß nicht, wie ich das sonst anders lösen sollte, also ohne Hilfsvariable.Code:;Programm ;CDurTonleiter rauf und runter spielen .include "m8def.inc" .def tmp = r16 ;Mein Universallregister .def helpSek = r17 .def tonwert = r19 ;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 ;Hier wird der nächste Ton geladen und in "tonwert" gespeichert ;Z-Zeiger wird um 1 erhöht, damit er beim nächsten mal den nächsten ;Ton lädt. Es wird hier auch verglichen,, ob der letzte Ton erreicht, ;wenn ja, dann springt er zu "endeTon" tonLaden: clr helpSek ;helpSek auf 0 setzen lpm ;Daten von tonleiter1: holen mov tonwert, lpm_reg ;erstes Byte in tmp verschieben 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 rjmp main ;sonst springe zu "main:" ;Hier wird der Timer gestoppt, indem wir den Prescaler auf 0 setzen endeTon: ldi tmp, (0<<CS02) ;Timer stoppen out TCCR0, tmp ;Die Hauptschleife, die sich immer wiederholt main: cpi helpSek, 0b11111111 ;Ist helpSek auf 255? (also 1 Sekunde um?) breq tonLaden ;dann lade den nächsten Ton rjmp main ;immer wieder zurück zu main springen ;Läuft Timer2 über, so wieder zaehlerSek um 1 erhöht und ;Timer2 neu vorgeladen pruefSek: push tmp ;tmp sichern in tmp, SREG push tmp ;SREG sichern ldi helpSek, 0b11111111 ;Hilfsvariable mit 255 belegen 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" pop tmp out SREG, tmp ;SREG wiederholen pop tmp ;tmp wiederholen reti ;Spring wieder dahin, 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 ;zu "timerSummer2:" springen timerSummer1: sbi PORTB, Summer ;wenn B.2 = 0 ist, dann auf 1 setzen ;Hier wird Timer0 mit dem aktuellen Tonwert vorgeladen timerSummer2: out TCNT0, tonwert ;Timer dementsprechen vorladen timerSummer3: 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
Hallo Thomas,
Daß Dein Programm noch nicht ganz Perfekt ist, ist auch kein Wunder,
überleg mal seit wann Du im Assembler programmierst?
Jetzt nicht traurig sein, es war nicht böse gemeint!
Hauptsache ist, daß es funktioniert, und verbessern kann man es immer noch.
Ich persönlich hätte es fast nur in den Interrupt Routinen gelöst.
Ob es besser oder schlechter als Deine Lösung ist, möchte ich hier nicht urteilen,
ich bin selber kein Profi, sondern genauso wie Du und die meisten hier ein Freak,
der von der Technik fasziniert ist.
Ich schreibe Dir meinen Ansatz, wie ich mir daß vorstelle, ok ?
Du kannst versuchen, das in einem Programm umzusetzen,
abe tue mir ein Gefallen, schreib bitte ein neues Programm, sonst kommt
wieder ein durcheinander dabei raus
Also:
ein Register, wo dein Tonwert gespeichert wird.
wie gehabt ein universallregister.
in loop zuerst mit lpm den ersten Ton in Tonwert einlesen, und den Timer0 damit laden.
als nächstes den Timer1 laden, (könnte auch in reset stehen denke mir)
und zum Schluß eine Endlosschleife.
die Timer0 Interruptroutine, ist sehr einfach, nur mit Tonwert neu laden und raus.
Timer1 Interruptroutine muß natürlich jetzt alles enthalten, was bis jetzt in Deinem Main:
gestanden hat, also
1. mit adiw den Z zeiger um eins erhöhen,
2. Schauen ob Du schon den letzten Ton hattest, wenn ja noch in der routine Timer stopen
und raus, sonst mit lpm Wert in den Register Tonwert schieben, Timer0 neu laden, und auch Interrupt verlassen.
Nach Tekeli Version kommt unter 2 dann halt Wert einlesen, nach 0 prüfen und dann entsprechend verzweigen.
Ob es schöner ist weiß ich nicht, aber es müßte auch so klappen (habe es nicht ausprobiert) , zum üben natürlich sehr gut geeignet.
Wenn Du,Ihr Lust habt dann könnt Ihr es versuchen.
Ich hoffe, daß ich es gut beschrieben habe, und vor allem, daß es so funktioniert![]()
Gruß Sebastian
Ihr habt beide andere Wege genommen um die Aufgabe zu lösen.
Beide haben vor und Nachteile.
Es wäre wohl nicht schwer zu sagen welche vor und nachteile es sind...Habt Ihr das übersehen, oder war das zu einfach?
![]()
Zu schwer würd ich sagen, wüsste nicht, welche Vorteile meine Version gegenüber Tekelis hätte.
So, hier der Code ohne Hilfsvariable - geht ja doch ohne
Man muss sich erstmal den Ablauf vor Augen halten, darin liegt denk ich noch mein größtes Problem. Aber das bekomm ich schon hin mit der Zeit.Code:;Programm ;CDurTonleiter rauf und runter 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 main: lpm ;Daten von tonleiter1: holen mov tonwert, lpm_reg ;erstes Byte in tmp verschieben - ersten Tonwert speichern rjmp main ;immer wieder zurück zu main springen ;Läuft Timer2 über, so wieder zaehlerSek um 1 erhöht und ;Timer2 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
Gruß
Thomas
Thomas,
aber Du hast Das Programm doch nicht neu geschrieben, oder?
z.B
.org OVF1addr
rjmp pruefSek ;Interruptvektor "pruefSek:"
mithin gehe ich davon aus daß pruefSek der Interrupthandler von Timer1 ist....
und schau was über pruefSek drüber steht![]()
Hmmmm
Hallo,
ich hab me Frage zu diesem hier:
beim ersten wird doch was in den Stack geschrieben und was ich nicht versteh beim zweiten wird das doch überschrieben! Wie kann man dann beides nacheinander wieder aus dem Stack holen mit diesem hier?:Code:push tmp ;Rette Universallregister in tmp, SREG ;Rette Statusregister push tmp
Gruß MichiCode:pop tmp ;stelle SREG wieder her out SREG, tmp pop tmp ;stelle Universalregister wieder her
Lieber Michael! ;o)
Du hast wohl noch immer nicht die xx Seiten durchgelesen, oder? *lol*
Die Adressen werden ans Ende des SRAMs gesetzt und wie ein Bücherstapel behandelt!
Du legst ein Buch drauf und nimmst eins runter, danach noch eins oder Du packst 3 drauf und nimmst 20 runter! *lol*
BücherSTAPEL!
Lesezeichen