[ATmega8]
Hallo
Ich muss mit Hilfe von Timer1 und den Interrupts einen
50Hz-Rechteckgenerator erzeugen.
Dafür verwende ich den Timer1 mit einem Prescaler von 1024.
Der Quarz hat 6MHz.
Der Interrupt wird bei einem Überlauf ausgelöst.
Berechnungen sind oben im Code.
Code:
Leider funktioniert das nicht, wie ich mir das vorstelle.
Der Port wechselt erst nach 11 SEKUNDEN.
Ich weiß, dass man 50 Hz nicht wirklich mit dem Auge sehen kann...
Was mache ich falsch??
Mit freundlichen Grüßen Denny.
Hi
>Leider funktioniert das nicht, wie ich mir das vorstelle.>Der Port wechselt erst nach 11 SEKUNDEN.
Das ist genau die Zeit, die der Timer zwischen 2 Overflow-Interrupts
braucht.
>LDI R16, 0b11111010 ;Low-Byte des Timer1 Wertes beschreiben >1024-6
= 00000011_11111010
>OUT TCNT1L, R16>LDI R16, 0b00000011>OUT TCNT1H, R16
Falsch. OUT TCNT1H muss als erstes beschrieben werden.
Das ganze geht wesentlich einfacher, wenn du den CTC-Mode benutzt.
MfG Spess
Hi
Dein Comparewert ist nicht korrekt. Muss $8D8B nicht $8D8C sein.
Warum schreibst du eigentlich so unverständlich?
>LDI R16, 0b00011101 -> ldi r16,High($8D8B)>LDI R16, 0b01001100 -> ldi r16,Low($8D8B)>LDI R16, 0b00010000 -> ldi r16,1<<OCIE1A>OUT TCNT1H, R16 ;Muss aber nicht sein>OUT TCNT1L, R16 ;Damit er von vorne anfängt
Unnötig. Wird automatisch gemacht.
MfG Spess
Gastofatz hat schon einen guten Vorschlag gemacht .... warum nimmst Du
den nicht an? Lass doch die Hardware alles machen! Dann sähe es nämlich
so aus (den Grund für die Wahl von OCR1A lass' ich Dir als Übung):
>LDI R16, 0b00011101 ;Komparator A von Timer1 High-Byte>OUT OCR1AH, R16>>LDI R16, 0b01001100 ;Komparator A von Timer1 Low-Byte>OUT OCR1AL, R16
Dasselbe, aber leichter zu lesen:
LDI R16, High(7500)
OUT OCR1AH, R16
LDI R16, Low(7500)
OUT OCR1AL, R16
Kollege spess53 hat übrigens recht: Der in das Output-Compare-Register
zu schreibende Wert muss um 1 kleiner sein (!) als der errechnete Wert.
So wäre es also ganz korrekt:
LDI R16, High(7500-1)
OUT OCR1AH, R16
LDI R16, Low(7500-1)
OUT OCR1AL, R16
Und das hier...
>CLR R16 ;Timer1 auf 0 setzen>OUT TCNT1H, R16 ;Muss aber nicht sein>OUT TCNT1L, R16 ;Damit er von vorne anfängt
...ist purer Nonsens. Lass TCNT1 in Frieden. Der Timer zählt im CTC-Mode
von selbst auf den Takt genau richtig (das ist ja der Sinn der Sache),
und Du bekommst damit die 50 Hz mit der höchstmöglichen Präzision
(16000000 MHz-Quarz --> 50.00000 Hz). Herumfummeln an TCNT1 kanns nur
schlechter machen.
Oh -- Du sollst ja Interrupts benutzen --- dann vergiss meine schöne
Methode mit CTC und WGM12=1 mal schnell! Ist sicher auch 'ne gute Übung
mit den Interrupts, selbst wenn damit Ressourcen verbraten werden.
Wenn du f=3,868400Mhz hast und eine Prescaler von 1024 wird der Timer
mit f/1024= 3777,734375 Hz getaktet. Bei f_out=25Hz sind für 1/50s genau
75,5546875 Takte pro Halbwelle.
Wenn du rückwärts zählst, lädst du den Timer1 mit 75 oder 76. Wenn du
aufwärts zählst dann lädst du den Timer1 mit 2^16 - 75 (76), weil beim
Erreichen der 0 der IRQ ausgelöst wird. Wenn das Ausgabebit nur
wechselt, erhältst du 25Hz. Für 50Hz selbst rechnen.
Mit Prescaler=1024 ist das relativ ungenau.
Für Prescaler=1 ist f/1= 3868400 Für 1/100s erhältst du genau 38684
Takte.
Also diese Zahl in den Timer laden, wenn du rückwärts zählst, dan das
Ausgabebit ändern. Beim Aufwärtszählen 2^16-38684 in den Timer laden.
Diese 50Hz sind so genau wie dein Quarz.
kl