Guten Tag, ich bin zur Zeit an einer Atmega32 Test Platine am testen.
Ganz Normaler Aufbau 8 LED's und 8 Taster alles Funktioniert Super.
Ich befasse mich zur Zeit mit dem Timer Interrupt. Verstehen tue ich das
eigentlich alles soweit, Precascler etc. Aber irgendwie zählt er nicht
richtig. Eingestellt habe ich den Prescaler auf 1ms.
Bei 16Mhz und 16Bit braucht der Timer 4,1mS um durch zulaufen bzw.
Überzulaufen. Und für 1mS startet der Zähler bei 49550.
Eingestellt habe ich den Timer so :
Der Prescaler
Was genau passiert denn, wenn du dein Programm laufen lässt?
Dein Timer zählt von 0 auf 49550 hoch, das sind 3,1 ms. So stehts auch
in den Kommentaren im Code; du scheinst aber zu glauben, dass er von
49550 auf 65536 hochzählt. Versuchs mal mit compare = 16000, das sollte
grob 1 ms sein.
Also die 8 LED's sind wie 2 Ampeln angeordnet. Gesteckt sind aber nur
6...
Über den scan_key Befehl im Timer lese ich die Taster aus und es
passiert auch das was es soll. Testweise LED's an aus. Die Zeit des
Timers reicht also aus die Tasten zu lesen.
Der Timer braucht aber viel zu lange um die Ampel zu wechseln hier auf
10 und 20 Sek eingestellt. Braucht aber das Vielfache.
> start_timer1(0,49550);> void start_timer1(int prescale,int compare)
49550 passt nicht in einen int.
Gewöhn dir die Datentypen int, long, etc. ab.
verwende die expliziten Dtaentypen
int16_t, uint16_t, int8_t, uint8_t, int32_t, uint32_t
und du wirst weniger oft von seltsamen Problemen gebissen.
(allerdings hast du insofern Glück, als sich im Endeffekt alles wieder
richtig zurechtrückt, weil mit int nur temporär eine andere
Interpretation der Bits passiert und sich nichts verändert. Trotzdem:
streiche int bei der AVR Programmierung zunächst mal aus deinem
Wortschatz)
Jakob schrieb:> Der Timer braucht aber viel zu lange um die Ampel zu wechseln hier auf> 10 und 20 Sek eingestellt. Braucht aber das Vielfache.
Das 'Vielfache' ist nicht zufällig ziemlich genau ein Faktor 16?
16Mhz versus 1Mhz Default Einstellung in den Fuses
Hallo Jakob,
ich lasse mir immer den passenden Prescaler und TOP-Counterwert für den
CTC-Mode vom Compiler berechnen.
Für
1
#define FREQUENZ 1000 // 1ms
Es gilt zu unterscheiden, wann die Bedingung erfüllt ist:
(uint16_t)(1.0* F_CPU /<prescale> /FREQUENZ) <= 65536
mit prescale E {1,8,64,256,1024}
Dann ist
OCR1A = ((uint16_t)(1.0*F_CPU /PRESCALER /FREQUENZ) -1);
Das "unterscheiden" macht der Preprozessor für uns.
Ist er bei ca. 13-16 Sek also kommt der Faktor 16 hin.
Der Timer bleibt wie vorher auch.
Geändert habe ich auf void start_timer1(uint16_t prescale,uint16_t
compare)
Hallo Jakob,
Die Obergrenze von 16000, ist so weit richtig, aber das ORC1A Register
wird nicht mit dem richtigen Wert geladen !
TIPP
Ist ORC1A = 0, dann erfolgt ein Interrupt alle 65536 Ticks.
Jakob schrieb:> Mit dem Faktor 16 ist glaube ich mein Problem. Wo mach ich das mit dem> "1Mhz Default Einstellung in den Fuses" ?
Alles klar.
Dein Brennprogramm hat einen entsprechenden Eintrag zum Thema Fuses.
Aber sei vorsichtig: mit einer falschen Einstellung kannst du dich aus
dem µC aussperren.
Zur Erklärung: die Angabe F_CPU ist nur die Information für den
Compiler, der einige Berechnungen darauf basierend macht (zb _delay_ms).
Es ist NICHT die Umstellung des µC! Die musst du selber machen. D.h. du
stellst den µC darauf ein, dass er einen Quarz benutzt und teilst dann
dem Compiler mittels F_CPU mit, auf welcher Frequenz der µC wirklich
läuft.
Atmel liefert seine AVR so aus, dass sie auf ca. 1Mhz interenem Takt
laufen. Wenn du etwas anderes willst (zb einen Quarz benutzen), dann
musst du an den Fuses eine entsprechende Einstellung vornehmen.
Da dein µC nach wie vor mit 1Mhz läuft, du aber mit 16Mhz gerechnet
hast, stimmen logischerweise deine errechneten Werte nicht.
Da stimmt auch noch was nicht
> Bei 16Mhz und 16Bit braucht der Timer 4,1mS um durch zulaufen
Soweit korrekt, wenn die Fuses erst mal stimmen
> Und für 1mS startet der Zähler bei 49550.
Du verwendest CTC Modus
D.h. da geht es nicht darum, bei welchem Wert der Timer starten muss,
damit bis zum Überlauf eine bestimmte Zeit vergeht.
Beim CTC Modus, geht es darum, bis zu welchem Wert (von 0 weg) der Timer
zählen muss, damit bei diesem Wert genau die von dir gewünschte Zeit
vergangen ist.
Die Berechnung ist ganz einfach.
Da du 16Mhz hast und einen Vorteiler von 1:
In 1 Sekunde würde der Timer bis 16000000 zählen (ignorier mal
Überläufe).
Wie weit kann er daher in 0.001 Sekunde (= 1Millisekunde) zählen?
1
1 .... 16000000
2
0.001 .... x
3
---------------------------
4
16000000 * 0.001
5
x = ------------------- = 16000
6
1
D.h. im CTC Modus lässt du den Timer 16000 Zählschritte machen. Danach
soll er seinen Interrupt auslösen und wieder bei 0 anfangen.
Bei 0 anfangen macht er alleine, denn genau das macht ja der CTC Modus.
Du brauchst nur noch die 16000 in OCR1A eintragen.
Vielen Dank für die Antworten, werde mich jetzt erst mal mit den FUSE's
auseinander setzen. Wenn es geklappt hat oder bei Fragen schreib ich es
hier rein.
Hab unter Device Programming den exteren Xtal nun auf 16mhz eingestellt
die Fuse müssten stimmen...er wartet jetzt die 10 sec zwischen den
Schaltungen aber die _delay_ms sind jetzt viel zu schnell.
Hab in allen c-files #define F_CPU 16000000UL damit er weiß das er damit
arbeiten soll, oder reicht es wenn ich es nur im Hauptfile schreibe. ?
>> ist das so richtig, damit der merkt das 16Mhz eingestellt sind ?
Ja. denn in util/delay.h wird F_CPU bereits benutzt. Daher muss zu
diesem 'Zeitpunkt' der Wert von F_CPU schon bekannt sein. Ergo sollte
die Defintion von F_CPU vor util/delay.h stehen.
Der Compiler liest den Programmtext von oben nach unten. So wie du ein
BUch liest. In einem Krimi geschieht ja auch vorher der Mord und erst
dann kommt die Auflösung durch den Kommisar.