ISR mit Quarz auslösen

OP #5524593
Lesenswert?

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
void TIMER(void)
7
{
8
TCCR1B|= (1<<CS12);          //Prescaler x256
9
TIMSK1 |= _BV(1<<TOIE1);      // activate overflow interrupts of timer1
10
TCNT1=0;
11
}
12

13
int main(void)
14
{
15
  DDRD=0x04;
16
  PIND|=0x04;
17

18
  TIMER();
19
  sei();
20

21
    while (1) 
22
    {
23
    }
24
}
25

26
volatile uint8_t toc =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
void TIMER(void)
8
{
9
TCCR1B|= (1<<CS12);          //Prescaler x256
10
TIMSK1 |= _BV(1<<TOIE1);      // activate overflow interrupts of timer1
11
TCNT1=0;
12
}
13

14
int main(void)
15
{
16
  DDRD=0x04;
17
  PIND|=0x04;
18

19
  TIMER();
20
  sei();
21

22
    while (1) 
23
    {
24
    }
25
}
26

27
volatile uint8_t toc =0;
28

29
ISR(TIMER1_OVF_vect)
30
{
31
if (toc<=31250)
32
{
33
toc++;
34
}
35
else 
36
{
37
PORTD ^= 0x04;
38
toc = 0;
39
}
40
}

Danke schonmal euch im voraus!
Gast #5524608
Lesenswert?

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.
OP #5524659
Lesenswert?

S. Landolt schrieb:
> Könnten wir das aktuelle Programm sehen?

Gerne.
1
#define F_CPU 1000000
2
#include <avr/io.h>
3
#include <avr/delay.h>
4
#include <avr/interrupt.h>
5

6
void TIMER(void)
7
{
8
TCCR0A= 0x00;           //Mode of Operation: Normal
9
TCCR0B= (1<<CS02)|(1<<CS00);   //Prescaler x1024
10
TIMSK0=(1<<TOIE0);
11
TCNT0=0;
12
}
13

14
int main(void)
15
{
16

17
DDRD=0x04;
18
PIND|=0x04;
19

20
TIMER();
21
sei();
22

23

24
    while (1) 
25
    {
26
    }
27
  return 0;
28
}
29

30
uint32_t toc=0;
31

32
ISR(TIMER1_OVF_vect)
33
{
34
if(toc<=976) toc++;      //muss noch eingestellt werden
35
else{
36
PORTD^=0x04;
37
toc=0;
38
}
39
}

Die LED blinkt alle 2/3 - 1/2 Sekunden nun.
Gast #5524697
Lesenswert?

Ehrlich gesagt habe ich jetzt den Überblick etwas verloren. Übernehmen 
Sie mal Folgendes, bei mir läuft das:
1
#define F_CPU 1000000
2
#include <avr/io.h>
3
#include <util/delay.h>
4
#include <avr/interrupt.h>
5

6
uint32_t volatile toc=0;
7

8

9
void TIMER(void)
10
{
11
TCCR0B= (1<<CS02);   //Prescaler 256
12
TIMSK0= (1<<TOIE0);
13
}
14

15
int main(void)
16
{
17

18
DDRD = (1<<PD3);
19

20
TIMER();
21
sei();
22

23
    while (1) 
24
    {
25
    }
26
}
27

28

29
ISR(TIMER0_OVF_vect)
30
{
31
if(toc<= 15) toc++;      //muss noch eingestellt werden
32
else{
33
PORTD ^= (1<<PD3);
34
toc=0;
35
}
36
}
#5524698
Lesenswert?

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.
Gast #5524718
Lesenswert?

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
OP #5524723
Lesenswert?

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 ?
#5524796
Lesenswert?

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.
OP #5524880
Lesenswert?

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.
Gast #5525013
Lesenswert?

> 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
Gast #5525028
Lesenswert?

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.
#5525091
Lesenswert?

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.
OP #5525120
Lesenswert?

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 ?
#5525191
Lesenswert?

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.
#5525229
Lesenswert?

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
1
ISR(TIMER0_OVF_vect)
2
{
3
  static uint8_t toc=0;
4
  if (toc <= .....
Gast #5525324
Lesenswert?

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.
OP #5527116
Lesenswert?

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.
Gast #5527167
Lesenswert?

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.
OP #5527409
Lesenswert?

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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren