So, hab die Ampel hinbekommen, aber leider nicht mit der Nutzung von:
Code:
timerwerte:
.dw 65536-7200, 65536-1800
Ich zeig hier erstmal den Code, der funktioniert. Also die rote und grüne Phase sollen logischerweise länger dauern als das Umstellen von gelb auf grün oder von gelb auf rot. Ihr wisst ja, wie eine Ampel funktioniert 
Code:
.equ time1 = 65536-7200
.equ time12 = 65536-1800
Meine 2 Timer, wie man sieht, der erste ist der lange Timer (für rote und rüne Phase) und der zweite Timer ist der kurze (für das Umschalten von gelb auf grün/rot)
Code:
ldi tmp, HIGH(time1)
out TCNT1H, tmp
ldi tmp, LOW(time1)
out TCNT1L, tmp
Timer wird bei "reset:" vorgeladen, also am Anfang ist die Ampel rot, deswegen der lange Timer. Bei der Interruptroutine (zeitum), also wenn der Timer überläuft, wird dann abgefragt:
Code:
zeitum:
push tmp ;tmp auf Stack sichern
in tmp, SREG
push tmp ;SREG auf Stack sichern
cpi statusAmpel, 0b00000010 ;Ist rot an?
breq rotgelban ;JA -> gelb dazuschalten
cpi statusAmpel, 0b00000110 ;Ist rot UND gelb an?
breq gruenan ;JA -> grün anmachen
cpi statusAmpel, 0b00001000 ;Ist grün an?
breq gelban ;JA -> gelb anmachen
rotan:
ldi tmp, HIGH(time1)
out TCNT1H, tmp
ldi tmp, LOW(time1)
out TCNT1L, tmp ;"TCNT1H" und TCNT2L"
ldi statusAmpel, 0b00000010 ;rot an
rjmp ende
rotgelban:
ldi tmp, HIGH(time12)
out TCNT1H, tmp
ldi tmp, LOW(time12)
out TCNT1L, tmp ;"TCNT1H" und TCNT2L"
adiw ZL, 1
ldi statusAmpel, 0b00000110 ;rot und gelb an
rjmp ende
gruenan:
ldi tmp, HIGH(time1)
out TCNT1H, tmp
ldi tmp, LOW(time1)
out TCNT1L, tmp ;"TCNT1H" und TCNT2L"
sbiw ZL, 3
ldi statusAmpel, 0b00001000 ;grün an
rjmp ende
gelban:
ldi tmp, HIGH(time12)
out TCNT1H, tmp
ldi tmp, LOW(time12)
out TCNT1L, tmp ;"TCNT1H" und TCNT2L"
adiw ZL, 1
ldi statusAmpel, 0b00000100 ;gelb an
Folgende Info erstmal:
0b00000010 <-- rot
0b00000110 <-- rot und gelb
0b00001000 <-- grün
0b00000100 <-- gelb
Also je nachdem was an ist, wechselt er die LEDs und lädt den Timer neu. Dieser Code funktioniert auch einwandfrei, nur nun wollt ich ja eigentlich mit dem Speichern arbeiten (wie oben schon erwähnt), aber irgendwie hab ich da einen logischen Fehler drinne, der sich einfach nicht finden lässt, also folgendes:
Ich brauche dann oben nur noch eine Konstante für den Timer:
Code:
.equ time1 = 65536-7200
[...]
ldi tmp, HIGH(time1)
out TCNT1H, tmp
ldi tmp, LOW(time1)
out TCNT1L, tmp
Dieser Timer wird wieder wie gewohnt im "reset:" vorgeladen (rot ist von Anfang an an.
Und hier der Code der Interruptroutine:
Code:
zeitum:
push tmp ;tmp auf Stack sichern
in tmp, SREG
push tmp ;SREG auf Stack sichern
cpi statusAmpel, 0b00000010 ;Ist rot an?
breq rotgelban ;JA -> gelb dazuschalten
cpi statusAmpel, 0b00000110 ;Ist rot UND gelb an?
breq gruenan ;JA -> grün anmachen
cpi statusAmpel, 0b00001000 ;Ist grün an?
breq gelban ;JA -> gelb anmachen
;Wenn alle drei Rechnungen != 0 ergeben, dann ist gelb an
rotan:
sbiw ZL, 3
ldi statusAmpel, 0b00000010 ;rot an
rjmp ende
rotgelban:
adiw ZL, 2
ldi statusAmpel, 0b00000110 ;rot und gelb an
rjmp ende
gruenan:
sbiw ZL, 3
ldi statusAmpel, 0b00001000 ;grün an
rjmp ende
gelban:
adiw ZL, 1
ldi statusAmpel, 0b00000100 ;gelb an
ende:
lpm
;TIMER1 wird neu geladen
mov tmp, lpm_reg
out TCNT1L, tmp
adiw ZL, 1
mov tmp, lpm_reg
out TCNT1H, tmp
out PORTB, statusAmpel ;Ampel richtig umschalten
pop tmp
out SREG, tmp
pop tmp
reti
Nun zur Erklärung, warum ich wie Z hoch oder runterzähle.
Meine Werte sind ja wie folgt beschrieben:
Code:
timerwerte:
.dw 65536-7200, 65536-1800
Am Anfang ist ja rot an, diese Lampe bleibt solange an, bis der Timer1 überläuft. Z zeigt zu diesem Zeitpunkt noch auf das LOW-Byte von 65536-7200 (oder?). Dann springt er zu "rotgelban:" dort addiert er den Zeiger mit 2, sodass er dann auf das LOW-Byte von 65536-1800 (der kurzen Zeit) zeigt. Wenn ich das nur mit 1 addieren würde, dann würde er ja auf das HIGH-Byte von der langen Zeit zeigen, also quatsch.
So, er schreibt als LOW (kurze Zeit) in TCNT1L, addiert Z mit 1 und schreibt dann HIGH (kurze zeit) in TCNT1H.
Jetzt zeigt Z auf das HIGH-Byte von der kurzen Zeit.
Beim nächsten Überlauf springt er zu "gruenan", dort subtrahiert er mit 3.
Also müsste er wieder auf das LOW-Byte von 65536-7200, also von der langen Zeit zeigen. Schreibt das dann in TCNT1L, addiert Z mit 1 und schreib das dann in TCNT1H usw. bis wieder rot ist.
Problem ist aber, dass die Zeit anscheinend nicht stimmt. Rot bleibt richtig an, da liegt noch nicht das Problem (ist ja auch oben bei "reset:" vorgeladen). Doch RotGelb bleibt genauso lange an, obwohl ich den Timer eigentlich mit der kurzen Zeit vorgeladen habe. Und das geht dann so weiter, ein totales Durcheinander.
Ich hoffe, ich hab das einißgermaßen verständlich rübergebracht, ist leider ein wenig lang geworden mein Beitrag 
Aber ich hoffe trotzem, dass mir einer bei meinem (kleinen?) Problem helfen kann.
Gruß
Thomas
Lesezeichen