Hallo,
ich habe ein Problem mit dem Timer bzw. der Clock auf einem Atmel
Evaluation Board 2. Die _delay_ms() Funktion wartet länger als erwartet.
Ich habe ein ATMega16PU angeschlossen und im AVR Studio die Option
SUT_CKSEL auf EXTHIFXTALRES_16KCK_64MS
gestellt. Bei der Option CKOPT bin ich mir nicht sicher, auf was ich das
stellen muss, hatte aber sowohl mit einem Häkchen als auch ohne keinen
Erfolg. In der Doku steht nämlich:
"For resonators, the maximum frequency is 8 MHz with CKOPT unprogrammed
and 16 MHz with CKOPT programmed." -> Also dachte ich, mache ich ein
Häkchen. In der auf der nächste Seite abgebildeten Tabelle steht aber
CKOPT = 0 für Frequenzen ab 1 MHZ.
Des Weiteren habe ich die Optimierung auf -Os gestellt.
Ich wollte eigentlich eine Infrarot-Fernbedienung programmieren bis ich
gemerkt habe, dass die Timings nicht stimmen. Daher habe ich mir erstmal
ein Minimalbeispiel erstellt, in dem ich eine LED einfach nur im 1
Sekunden Rhythmus toggle.
1
#ifndef F_CPU
2
#define F_CPU 16000000UL
3
#warning keine F_CPU definiert
4
#endif
5
6
#include<stdint.h>
7
#include<avr/io.h>
8
#include<avr/interrupt.h>
9
#include<util/delay.h>
10
11
intmain(void)
12
{
13
DDRD=0xff;
14
15
while(1)
16
{
17
_delay_ms(1000);
18
PORTD^=(1<<PD5);
19
}
20
}
Innerhalb von 26 Sekunden blinkt die LED allerdings nur 10 Mal. Sie
sollte ja eigentlich 13 mal blinken.
Kann mir jemand sagen, ob ich etwas vergessen habe?
Gruß
Michael
Michael schrieb:> Kann mir jemand sagen, ob ich etwas vergessen habe?
Ja, du hast vergessen zu sagen, was du denn als frequenzbestimmendes
Bauteil nimmst. Resonatoren sind etwas anderes als Quarze und welche
Quarzfrequenz du benutzt, hast du uns nicht mitgeteilt.
Für den Fall, das du einen 'echten' Quarz und keinen Keramikresonator
benutzt, kannst du alle Resonator Optionen abschalten. Lediglich die
beiden 22pF Kondensatoren sollten wie immer nach Datenblatt am Quarz
hängen.
Wenn du AVR Studio benutzt, solltest du die korrekte Frequenz auch in
den Projektoptionen eintragen.
Schau mal in Deine delay.h, ob die 1000 als Argument akzeptiert werden:
"The maximal possible delay is 262.14 ms / F_CPU in MHz."
Das F_CPU wird in den Projekteigenschaften eingetragen.
Matthias Sch. schrieb:> Lediglich die> beiden 22pF Kondensatoren sollten wie immer nach Datenblatt am Quarz> hängen.
Das war ja wohl nix.
Wenn man schon einen genauen Takt haben will, dann sollten die zum
Quarz, dem Controller und der Platine passenden Kondensatoren richtig
verbaut sein.
Hallo und danke soweit für die Antworten,
die Frequenz habe ich nun als neues Symbol in den Projekteigenschaften
eingegeben. Leider hat sich nichts verändert.
Matthias Sch. schrieb:> Ja, du hast vergessen zu sagen, was du denn als frequenzbestimmendes> Bauteil nimmst.
Stimmt: Ich habe ein 16 MHz Quarz auf der Platine und direkt daneben
befinden sich die beiden 22pF Kondensatoren.
Matthias Sch. schrieb:> Für den Fall, das du einen 'echten' Quarz und keinen Keramikresonator> benutzt, kannst du alle Resonator Optionen abschalten.
Welche Resonator-Optionen meinst du? Die SUT_CKSEL Option? Und was
meinst du mit abschalten?
Pete K. schrieb:> Schau mal in Deine delay.h, ob die 1000 als Argument akzeptiert werden
Die Funktion arbeitet bis zu "262.14 ms / F_CPU in MHz" genau, danach
mit einer Genauigkeit von 1/10 s. Sollte also auch kein Problem sein.
Trotzdem habe ich zur Sicherheit jetzt 5 mal hintereinander ein
_delay_ms(200) statt dem einmaligen Aufruf von _delay_ms(1000). Leider
auch hier keine Veränderung.
Gibt es sonst noch Vorschläge?
Gruß Michael
Michael schrieb:> Gibt es sonst noch Vorschläge?
Schau ins Datenblatt, Kapitel Timer und schreib dir deine eigene
Delay-Funktion.
Und nein, das ist kein Scherz, ist ja auch nicht sonderlich schwer...
Michael schrieb:> Gibt es sonst noch Vorschläge?
Mein nächster wäre jetzt, mal den internen Oszillator zu aktivieren mit
seinen 8 Mhz, die Projekteinstellungen und F_CPU entsprechend anzupassen
und dann nochmal zu probieren, ob _delay_ms(1000) weiterhin zu langsam
ist.
Rein rechnerisch müsste dein 16Mhz Quarz nämlich im Moment mit ca. 12,3
Mhz laufen und das geht einfach nicht (egal, welchen Wert die beiden C
haben), es sei denn, die Hersteller haben da ne falsche Frequenz
raufgedruckt. Hast du noch andere Quarze bekannter Frequenz da? Auch
damit könntest du nochmal gegenchecken.
Ach, _delay_ms() funktioniert übrigens richtig mit der -Os Optimierung,
da hätte ich ja mal früher drauf kommen können.
Hallo,
Georg G. schrieb:> #define __HAS_DELAY_CYCLES 0
Habe ich ganz oben eingefügt, hat aber keinen Unterschied gemacht.
Matthias Sch. schrieb:> Mein nächster wäre jetzt, mal den internen Oszillator zu aktivieren mit> seinen 8 Mhz, die Projekteinstellungen und F_CPU entsprechend anzupassen> und dann nochmal zu probieren, ob _delay_ms(1000) weiterhin zu langsam> ist.
Habe ich ebenfalls mit allen Frequenzen des internen Oszillator
ausprobiert, aber es hat sich auch hier nichts verändert.
Kaj schrieb:> Schau ins Datenblatt, Kapitel Timer und schreib dir deine eigene> Delay-Funktion.
Meinst du eine richtige Delay-Funktion oder einen Interrupt gesteuerten
Ablauf? Letzteres habe ich implementiert und siehe da: Die LED blinkt im
1 Sekunden-Takt.
1
#include<stdint.h>
2
#include<avr/io.h>
3
#include<avr/interrupt.h>
4
#include<util/delay.h>
5
6
volatileuint16_tcounter;
7
8
ISR(TIMER0_OVF_vect)
9
{
10
// F_CPU = 16 MHz, Prescaler 1024 -> 15625 clock steps / 256 = 61 interrupts in einer Sekunde
11
if(counter++>=61)
12
{
13
counter=0;
14
PORTD^=(1<<PD5);
15
}
16
}
17
18
intmain(void)
19
{
20
counter=0;
21
DDRA=0xff;
22
23
// Prescaler 1024
24
TCCR0|=((1<<CS02)|(1<<CS00));
25
TCCR0&=~(1<<CS01);
26
27
TCNT0=0;
28
TIMSK|=(1<<TOIE0);
29
30
sei();
31
32
while(1)
33
{
34
}
35
}
Der Quarz schwingt also richtig, der Prozessor kann es auch verarbeiten.
Anscheinend ist die _delay_ms() Funktion wirklich ziemlich ungenau.
Im Kommentar der Funktion steht zwar, dass die Funktion bei dieser
Frequenz bis ca. 16 ms genau arbeitet, danach aber immer noch mit einer
1/10 s Genauigkeit bis zu 6.5 Sekunden, was ich in meinem Fall nicht
bestätigen kann.
Danke für eure Vorschläge
Michael
Hast Du auch wirklich alle F_CPU Befehle aus den .c und .h Dateien
gelöscht?
Gibt der Compiler irgendwelche Warnungen aus?
Poste mal Dein ganze Projekt als zip-File.
Matthias Sch. schrieb:> Ach, _delay_ms() funktioniert übrigens richtig mit der -Os Optimierung,> da hätte ich ja mal früher drauf kommen können.
Hast du nochmal geschaut, welche Einstellung du für die Optimierung
nimmst? Wie erwähnt, gehts m.W. nur mit "-Os" richtig.