So, hab die Ampel hinbekommen, aber leider nicht mit der Nutzung von:
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 funktioniertCode:timerwerte: .dw 65536-7200, 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:.equ time1 = 65536-7200 .equ time12 = 65536-1800
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:ldi tmp, HIGH(time1) out TCNT1H, tmp ldi tmp, LOW(time1) out TCNT1L, tmp
Folgende Info erstmal: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
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:
Dieser Timer wird wieder wie gewohnt im "reset:" vorgeladen (rot ist von Anfang an an.Code:.equ time1 = 65536-7200 [...] ldi tmp, HIGH(time1) out TCNT1H, tmp ldi tmp, LOW(time1) out TCNT1L, tmp
Und hier der Code der Interruptroutine:
Nun zur Erklärung, warum ich wie Z hoch oder runterzähle.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
Meine Werte sind ja wie folgt beschrieben:
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.Code:timerwerte: .dw 65536-7200, 65536-1800
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







Zitieren

Lesezeichen