Hallo Zusammen,
ich habe zwei Fragen:
1.
Ich möchte eine LED an PinD3 toggeln, sobald die if-Bedingung in der ISR
erfüllt ist. Da ich mit dem interenen Oszillator den Interrupt auslöse,
welcher eine Freuquenz von 1MHz hat, sollte die LED mit dem Prescaler
von 256 jede Sekunden blinken.
1000000/256=3906
Leider tut sie das erst 15-16 Sekunden. Wieso passiert das?
1
#define F_CPU 1000000
2
#include<avr/io.h>
3
#include<avr/interrupt.h>
4
#include<util/delay.h>
5
6
voidTIMER(void)
7
{
8
TCCR1B|=(1<<CS12);//Prescaler x256
9
TIMSK1|=_BV(1<<TOIE1);// activate overflow interrupts of timer1
10
TCNT1=0;
11
}
12
13
intmain(void)
14
{
15
DDRD=0x04;
16
PIND|=0x04;
17
18
TIMER();
19
sei();
20
21
while(1)
22
{
23
}
24
}
25
26
volatileuint8_ttoc=0;
27
28
ISR(TIMER1_OVF_vect)
29
{
30
if(toc<=3906)
31
{
32
toc++;
33
}
34
else
35
{
36
PORTD^=0x04;
37
toc=0;
38
}
39
}
2. Ich habe einen Quarz (16MHz) parallel an XTAL1 und XTAL2
angeschlossen. Zusätzlich (wie im Datenblatt steht) jeweils hinter XTAL1
und XTAL2 einen 22pF Kondensator auf Masse. Den Quarz hab ich am anfang
als Taktgeber definiert. aber auch hier sind es immernoch die 15-16
Sekunden. Wieso? Ich weiß eigentlich müsst ich erstmal die 1. Frage
klären, allerdings hab ich das Gefühl das hiermit zusammenhängende
Fragen geklärt werden können.
1
#define XTAL 16000000
2
#define F_CPU XTAL
3
#include<avr/io.h>
4
#include<avr/interrupt.h>
5
#include<util/delay.h>
6
7
voidTIMER(void)
8
{
9
TCCR1B|=(1<<CS12);//Prescaler x256
10
TIMSK1|=_BV(1<<TOIE1);// activate overflow interrupts of timer1
Meik S. schrieb:> Den Quarz hab ich am anfang> als Taktgeber definiert. aber auch hier sind es immernoch die 15-16> Sekunden. Wieso?
Weil du vermutlich im Controller die Fuses für deine gewünschte
Quarz-Einstellung nicht gesetzt hast.
Freundlich wäre es auch den Controller-Typ anzugeben.
S. Landolt schrieb:>> uint8_t toc>> toc<=3906>> Passt das zusammen?
Leider weiß ich nicht was du damit meinst.
S. Landolt schrieb:> Und überhaupt, der Teiler ist doch 256* TOP von Timer1 des unbekannten> uC.
atmega328p. Ist die Zählfrequenz des Timers nicht F_CPU/Prescaler? nach
Erreichen dieses Quotienten läuft er über und die ISR wird doch
ausgelöst ?!
S. Landolt schrieb:>> uint8_t toc>> toc<=3906>> Passt das zusammen?
achso er kann nur bis 255. ja ok dann müsste es aber doch mit uint32_t
funktionierten? allerdings macht er immernoch das selbe.
Die Zahl 3906 passt nicht in 8 bits.
Der Timer läuft mit 1 MHz/256, zählt bis zum Overflow, bei einem
ATmega328 hat er 16 bit, zählt also bis 2^16, und damit komme ich auf
16.777 s.
Genau 1 Sekunde ist so nicht zu erreichen, dazu bräuchte man den
CTC-Modus.
Ungefähr bekommt man es mit dem Prescaler = 1 hin: 1 MHz / 65536 =
15.259/s, also toc bis 15 zählen lassen.
ich hab das volatile wieder angefügt. Allerdings passiert einfach nichts
wenn ich die Bedingung ändere in der If-Bedingung. nur wenn ich den
Prescaler verändere.
Beim Prescaler von 1024 und 1MHz Takt wird das TCNT0 etwa 976 mal pro
Sekunde erhöht.
Der Timer Overflow Interrupt findet aber erst nach 256 Erhöhungen statt.
D.h. dass nach 256/976stel Sekunde die Variable TOC um eins erhöht wird.
Bis die Varibale toc den Wert 15 erreicht hat, muss die ISR also 15 mal
aufgerufen worden sein, d.h. 15* 256/976 ~ 4 Sekunden
Demnach passiert nicht nix, sondern das Toggeln sollte so alle 4
Sekunden stattfinden.
hi,
der Herr Landolt schreib:
>Oder den Timer0 (mit seinen 8 bit (2^8 = 256)) nehmen,>wieder Prescaler =1 und toc bis 3906 (Überraschung) zählen lassen.
wie passt denn das zu deinem Prog ?
>TCCR0B= (1<<CS02)|(1<<CS00); //Prescaler x1024>TIMSK0=(1<<TOIE0);
die ISR wurde ja schon angemerkt.........
Hirn in Urlaubsstimmung?
Viel Erfolg, Uwe
S. Landolt, das Program funktioniert bei mir auch. Leider verstehe ich
einfach nicht was daran so groß anders ist bis auf Timer0 und dem
Prescaler.
Ich würde jetzt gerne noch den Takt mit dem Quarz erhöhen auf 16MHz. ist
das mit :
1
#define XTAL 16000000
2
#define F_CPU XTAL
einfach gemacht oder muss man noch andere Sachen dort beachten ?
kann mir jemand erklären wie man dieses Fuse richtig setzt. in der
Literatur liest man oft, dass wenn man die falschen Fuses setzt, der µC
nicht mehr zu gebrauchen ist. Ich benutze Atmel Studio 7 und einen
ISP-Programmer.
Sie benötigen für das Fuse-Low-Byte den Wert 0xF7.
Wie Sie den allerdings in den ATmega328 bekommen, muss ein Anderer
erklären, ich arbeite hier mit einem Selbstbauprogrammiergerät.
Sieht zumindest nicht schlecht aus, aber mehr kann ich leider nicht dazu
sagen.
Falls Sie noch am alten Problem interessiert sind:
0x04 geht nicht auf PD3, sondern auf PD2.
Gehe in aller Ruhe nochmal wirklich Bit für Bit alle
Konfigurationsregister durch.
Kurze Zusamenfassung:
Meik S. schrieb:> TCCR1B|= (1<<CS12); //Prescaler x256
-Das ist das einzige Bit das du setzt. Der Rest ist damit auf
Defaultwert.
Frage dich in welchem Modus der Timer dann ist.
-F_CPU setzt NICHT die Frequenz. Damit wird nur eine Konstante
definiert die man dann in Formeln verwenden kann, damit man beim Ändern
des Taktes *per "Hardware"* nicht den Code durchsuchen muß um verstreut
Anpassungen vorzunehmen, sondern nur noch an einer Stelle die gewählte
Frequenz bei F_CPU eintragen mußt. Das spart Arbeit und ist weniger
Fehleranfällig, weil man nichts übersieht (hoffentlich).
Aber nochmal zum Mitschreiben. damit setzt du nicht den tatsächlichen
Takt. Es ist eine Konstante, nicht mehr!
Die Frequenz wählst du per Hardware, z.B. Quarz, Fuse für Tacktquelle
und Clock-Divider etc.
an Meik S.:
Ihre Zeile deckt sich ja mit der entsprechenden im Artikel hier im Forum
"AVR Fuses", sollte also stimmen, und der Wert 0xF7 ist korrekt, dafür
garantiere ich.
S. Landolt schrieb:> an Meik S.:> Ihre Zeile deckt sich ja mit der entsprechenden im Artikel hier im Forum> "AVR Fuses", sollte also stimmen, und der Wert 0xF7 ist korrekt, dafür> garantiere ich.
Ich habe jetzt das LFuse auf 0x07 gesetzt den Rest habe ich so gelassen.
Den µC erreiche ich nun nicht mehr. AVRDUDE gibt mir zu mindestens
keinen Kontakt mehr an.
Nichts für Ungut aber würde doch gerne genau wissen ob das so gemacht
wird, da die Dinger doch ein wenig kosten und ich jetzt erstmal nicht
mehr weitermachen kann.
> Ich habe jetzt das LFuse auf 0x07 gesetzt ...
Wie kommen Sie auf diesen Wert? Sollte aber trotzdem funktionieren, es
ist der 'Full Swing Crystal Oscillator' eingestellt; sicher, dass der
Quarz richtig angeschlossen ist?
Zum bisherigen Verlauf:
> Leider verstehe ich einfach nicht was daran so groß anders ist ...
Es waren zu viele Fehler auf einmal, was den Überblick erschwerte; im
ursprünglichen Programm:
- 0x04, d.h. PD2 statt PD3
- 3906 in uint8_t
- Zeitverhältnis: 1 MHz /256 /2^16 /3906 = 1.526 * 10^-5 Hz = 65532 s
später kamen hinzu:
- fehlendes volatile
- fehlende ISR, es war die für Timer1 definiert statt für Timer0
PS:
Ihre Verärgerung kann ich verstehen, aber nehmen Sie es positiv und
verbuchen Sie es unter 'Lehrgeld': in diesem Metier geht nichts 'mal
eben so ungefähr', auch kleine Fehler, selbst Nachlässigkeiten ziehen
Konsequenzen nach sich; vor allem sollte man nie versuchen, zwei
Schritte auf einmal zu machen.
Beginneen wir doch mal ganz von vorn bei den Grundlagen, systematisch.
Welches Betriebsystem nutzt du?
Welches Board zum Programmieren nutzt du?
Hast du früher schonmal erfolgreich mit den Fuses gearbeitet?
Du scheinst Einsteiger zu sein. Ist deine Ausrüstung jungfräulich oder
hat es früher bei vorangehenden Projekten einwandrei funktioniert?
Manche Hard-/Softwarekombinationen funktionieren nicht fehlerfrei, was
besonders gemein ist. Ein "funktioniert gar nicht" ist offenichtlicher
und fällt schneller auf. Die Wackelkandidaten sind da etwas fieser.
An S. Landolt:
Ja den habe ich gelesen. Würde es zu Not auch so versuchen, habe
mittlerweile mir aber einen neuen 328p organisiert.
Außerdem habe ich mich verschrieben. Ich meinte 0xF7.
Ja ist jetzt auch nicht so wild dass der vielleicht erstmal nicht mehr
nutzbar ist. Möchte aber nicht 10 mal den selben Fehler machen.
an Carsten R.:
Das verstehe ich nicht. Wieso sollte das nicht funktionieren wenn ich
sonst soweit alles Flashen könnte.
Also:
-atmel Studio 7
-avrdude (müsste die neuste sein)
-"ehajo" isp stick (libusb_win32 oder so)
Wo könnte dort der Fehler liegen ?
Wenn das Wieso so offensichtlich wäre, gäbe es solche Bugs nicht. Das
sind unterschiedliche bereiche die unterchiedlich angesprochen werden.
Wenn da ein Bug ist.... Wenn das Timing grenzwertig ist... etc. Es gibt
Programmer, bei denen AVRDude den Takt nicht richtig einstellen kann.
Dann gab es Probleme mit einzelnen Windows-Versionen, mal mit dem 64 Bit
Treiber, etc.
Darum lese ich immer zuerst die Fuses, schaue ob sie Sinn machen und
ändere sie dann. Dabei fällt dann auch sofort auf, ob die Anzeige
invertiert ist oder nicht. 1 ist uprogrammiert und 0 ist programmiert.
Bei Ponyprog setzt man z.B. einen Haken für eine 0 (Programmiert). Du
verwendest zwar ein Ponyprog, daber das ist noch ein Beispiel für:
"Hat doch sonst immer funktioniert."
Es gibt also immer wieder überraschungen, besonders wenn man etwas zum
ersten mal nutzt. Daher die Frage nach der Jungfräulichkeit.
Und wenn ich mich dann auch mal ganz dumm anstelle (vor meinem ertten
Kaffee), dann stelle ich den AVR auf einen Quarz ein, der auf der
Platine gar nicht vorhanden ist.
Überraschungen gibt es viele. Darum frage ich so kleinlich und penibel.
Ein systematisches routiniertes Vorgehen ist oberstes Gebot, nicht erst
wenn es hakt.
Bei einem "neuen Arbeitsplatz" würde ich empfhlen erst einmal ein
Testprogramm zu flashen das erwiesenermaßen funktioniert, z.B. eine
Zählschleife die eine LED blinken läßt ohne Interrupts und Timer. Das
gibt es in vielen Tutorials. Da gbt es dann auch kaum was falsch zu
konfigurieren und man "sieht dann den Takt". Wie du gemerkt hast, spielt
bei dn Timern die Konfiguration an mehreren Stellen mit rein, Prescaler,
8-Bit-Modus oder mehr Bits, Zählgrenze, welcher Interrupt (Overflow oder
Compare-Match)...
Das macht man dann vorab, um die Installation zu testen. Sonst sucht man
später Programmfehler obwohl es an anderer Stelle hakt.
Der Vollständigkeit halber:
"toc" muss nicht volatile sein.
Es wird nur in der ISR gelesen/geschrieben, nie von ausserhalb, also
kann auch beim Zugriff nichts schiefgehen wenn der Compiler den Wert
irgendwo zwischenspeichert.
Der Klarheit halber würde ich die Variable dann aber als "static"
Variable in der ISR deklarieren, also
Einen weiteren Fehler hatte ich bei meiner Aufstellung noch vergessen,
er sei nachgetragen, um ihn in Zukunft zu vermeiden:
> TIMSK1 |= _BV(1<<TOIE1); // activate overflow interrupts of timer1
Das '1<<' konterkariert das 'BV'.
(In der Summe war das denn doch zuviel auf einmal für mich, und so fand
ich mich zwischenzeitlich in einer ähnlichen Lage wie Buridans Esel
wieder, nicht wissend, wo anfangen)
> "toc" muss nicht volatile sein.
Okay, sorry. Eigentlich programmiere ich in Assembler, mein bisschen C
habe ich mir hier im Forum angeeignet.
Max schrieb:> Das ist eine Schreibweise, die die Fehler begünstigt.> Besser so:> PORTD ^= (1<<PD2);
Da ich weiß, welcher µC genutzt wird, wage ich zu behaupten, dass dieses
noch viel besser ist, um den betreffenden Pin zu togglen:
PIND = _BV(PD2);
Arduino Fanboy D. schrieb:> PIND = _BV(PD2);
_BV ist ein Macro, das ist kein "C". Geschmackssache natürlich, aber ich
denke, mit Macro wird Quelltext weniger verständlich. D.h. solche
Schreibweise hilft weniger, Fehler zu vermeiden. Besser doch
An alle noch interessierten:
das LFUSE muss auf 0x66 (zumindest wenn das Datenblatt vom 328p genutzt
wird) gestellt werden für die Verwendung eines Standartquarz (Full Swing
Crystal).
Da ich ein 16MHz Quarz nutze läuft die Uhr jetzt doppelt so schnell.
Ich hatte gedacht, Sie wollen die vollen 16 MHz nutzen. Mit 0x66 ist
CKDIV8 eingeschaltet (zumindest wenn Sie nicht softwaremäßig
umschalten), also läuft der ATmega328 mit 2 MHz.
Nochmal ausführlicher: Ihr ATmega328 steht mit dem 0x66 jetzt auf
'Ceramic resonator, BOD enabled', und da lese ich (bei 1/8 der
Frequenz):
These options are intended for use with ceramic resonators and will
ensure frequency stability at start-up. They can also be used with
crystals when not operating close to the maximum frequency of the
device, and if frequency stability at start-up is not important for the
application.
0xF7 wäre 'Crystal Oscillator, slowly rising power' gewesen, also die
sicherste Einstellung, bei voller Frequenz.
S. Landolt schrieb:> Ich hatte gedacht, Sie wollen die vollen 16 MHz nutzen. Mit 0x66 ist> CKDIV8 eingeschaltet (zumindest wenn Sie nicht softwaremäßig> umschalten), also läuft der ATmega328 mit 2 MHz.
Nein das hatte ich aber auch nie behauptet, nur dass ich den Quarz
nutzen möchte.
S. Landolt schrieb:> Nochmal ausführlicher: Ihr ATmega328 steht mit dem 0x66 jetzt auf> 'Ceramic resonator, BOD enabled', und da lese ich (bei 1/8 der> Frequenz):> These options are intended for use with ceramic resonators and will> ensure frequency stability at start-up. They can also be used with> crystals when not operating close to the maximum frequency of the> device, and if frequency stability at start-up is not important for the> application.>>> 0xF7 wäre 'Crystal Oscillator, slowly rising power' gewesen, also die> sicherste Einstellung, bei voller Frequenz.
Im Datenblatt steht:
These options should only be used when not operating close to the
maximum frequency of the device, and
only if frequency stability at start-up is not important for the
application. These options are not suitable for
crystals.
Daher habe ich die Standarteinstellung gelassen. Wenn das aber der
sichere Weg ist werde ich LFUSE mit 0xF7 besetzen.