Forum: Compiler & IDEs Timer will nicht wie ich will


von Jochen Schemmel (Gast)


Lesenswert?

Hi,

warum leuchtet bei dem unten angehängten Code die LED, anstatt wie 
gewünscht zu blinken?

Wenn ich die LED über die Hauptschleife mit delay_ms toggle funzt es 
wunderbar. Über den Timer mit Interrupt leider nicht. Ich mache bestimmt 
einen #@!-blöden Fehler, oder?

MFG

Jochen


Hier der Code:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
void initTimer(void);
5
6
int main(void)
7
{
8
  DDRD |= (1<<DDD5);
9
  PORTD |= (1<<PD5);   /*PortD-Pin5 ist Ausgang, Startzustand High*/
10
  
11
  sei();                          /*globale Interrupts einschalten*/
12
  initTimer();
13
14
  for(;;);
15
  return 0;
16
}
17
18
void initTimer(void)
19
{
20
  /*F_CPU = 16MHz*/
21
  TCCR0 = (1<<WGM01) | (1<<CS01) | (1<<CS00);   /*CTC, prescaler 64*/
22
  OCR0 = 250;             /*16MHz/64=250kHz; 250kHz/250=1kHz -> 1ms*/
23
  TIMSK |= (1<<OCIE0);                       /*Interrupt aktivieren*/
24
}
25
26
ISR(TIMER0_COMP_vect)
27
{
28
  static volatile unsigned int count;
29
  count++;
30
  if(count==1000);                             /*nach einer Sekunde*/
31
  {
32
    PORTD^=(1<<PD5);                                  /*Pin toggeln*/
33
    count=0;
34
  }
35
}

von Jochen Schemmel (Gast)


Lesenswert?

NACHTRAG:

Es ist ein Atmega32 mit 16MHz auf einem Pollin Evaluationboard ver. 
2.01, das ganze unter Avrstudio 4.15 mit GCC.

von Karl H. (kbuchegg)


Lesenswert?

Jochen Schemmel schrieb:

> ISR(TIMER0_COMP_vect)
> {
>   static volatile unsigned int count;

    static volatile unsigned int count = 0;

Variablen, mit Ausnahme von globalen Variablen, kommen nicht automatisch 
mit einem 0-Wert zur Welt.


Hast du schon kontrolliert, ob die ISR überhaupt aufgerufen wird?
1
int main(void)
2
{
3
  DDRD |= (1<<DDD5) | (1<<DDD6);
4
  PORTD |=  ( 1 << PD5 );   /*PortD-Pin5 ist Ausgang, Startzustand High*/
5
  PORTD &= ~( 1 << PD6 );   /* just to make sure ... */
6
7
....
8
9
ISR(TIMER0_COMP_vect)
10
{
11
  PORTD |= 1 << PD6;
12
  ...

Wenn die ISR aufgerufen wird, muss PD6 auf High sein.

von Jochen Schemmel (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
>> ISR(TIMER0_COMP_vect)
>> {
>>   static volatile unsigned int count;
>
>   static volatile unsigned int count = 0;
>
>Variablen, mit Ausnahme von globalen Variablen, kommen nicht automatisch
>mit einem 0-Wert zur Welt.

Wenn ich "static volatile unsigned int count" in der ISR mit "0" 
initialisiere, wird die Variable dann nicht trotz "static" bei jeden 
Sprung in die ISR neu auf "0" gesetzt und somit nie auf 1000 
hochgezählt?
Ich habe die Variable mal aus der ISR heraus genommen und global 
gemacht. Das hat aber leider nichts an der Situation geändert, dass die 
LED nicht Blinkt.


>Hast du schon kontrolliert, ob die ISR überhaupt aufgerufen wird?
>
> int main(void)
> {
>   DDRD |= (1<<DDD5) | (1<<DDD6);
>   PORTD |=  ( 1 << PD5 );   /*PortD-Pin5 ist Ausgang, Startzustand High*/
>   PORTD &= ~( 1 << PD6 );   /* just to make sure ... */
>
>  ...
> ISR(TIMER0_COMP_vect)
> {
>   PORTD |= 1 << PD6;
>   ...
> Wenn die ISR aufgerufen wird, muss PD6 auf High sein.

Habe es ausprobiert. Eine LED an PD6 leuchtet auf, die ISR wird 
aufgerufen.

Jetzt sehe ich aber die LED an PD5 minimal schwächer leuchten als die an 
PD6. Das bedeutet wohl, dass sie sehr schnell blinkt. Dies kann ich dann 
aber auch nicht nachvollziehen.

Diese Rechnung mit dem Timer stimmt doch so, oder?
16Mhz Takt / 64 ergeben einen 250kHz Timertakt. Wenn der Timer mit 
250kHz bis 250 gezählt hat, dann entspricht das einer Frequenz von 1kHz, 
also einer zeit von 1 ms. Wenn ich in der ISR eine Variable bis 1000 
hochzähle ist etwa 1 Sekunde vergangen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Karl heinz Buchegger schrieb:

> Variablen, mit Ausnahme von globalen Variablen, kommen nicht automatisch
> mit einem 0-Wert zur Welt.

Hier irrt der meister: für Variablen, die "static" deklariert sind,
gelten in dieser Hinsicht gleiche Regeln wie für globale Variablen.

von Karl H. (kbuchegg)


Lesenswert?

Jörg Wunsch schrieb:
> Karl heinz Buchegger schrieb:
>
>> Variablen, mit Ausnahme von globalen Variablen, kommen nicht automatisch
>> mit einem 0-Wert zur Welt.
>
> Hier irrt der meister: für Variablen, die "static" deklariert sind,
> gelten in dieser Hinsicht gleiche Regeln wie für globale Variablen.

Erwischt :-)
Aber wenigstens zur 'guten Seite hin' vertan. (Schweiß von der Stirn 
wisch :-)

von Karl H. (kbuchegg)


Lesenswert?

Jochen Schemmel schrieb:

> Diese Rechnung mit dem Timer stimmt doch so, oder?
> 16Mhz Takt / 64 ergeben einen 250kHz Timertakt. Wenn der Timer mit
> 250kHz bis 250 gezählt hat, dann entspricht das einer Frequenz von 1kHz,
> also einer zeit von 1 ms. Wenn ich in der ISR eine Variable bis 1000
> hochzähle ist etwa 1 Sekunde vergangen.

Müsste stimmen.

16000000 / 64 = 250000    Prescaler
250000 / 250  = 1000      OCR
1000 / 1000   = 1         Teiler in der ISR

in Summe teilst du bis auf 1 Hz runter. Sollte also passen.

Hmmmmmm

von Karl H. (kbuchegg)


Lesenswert?

Jochen Schemmel schrieb:


> Habe es ausprobiert. Eine LED an PD6 leuchtet auf, die ISR wird
> aufgerufen.

Um das interpretieren zu können: Wie sind deine LED verschaltet?
Leuchten die bei 0 am Port oder bei 1 am Port?

(Bin von einer 1 am Port ausgegangen)

von Jochen Schemmel (Gast)


Angehängte Dateien:

Lesenswert?

Ich habe jetzt zum wiederholten male das Datenblatt gewälzt und bin 
relativ sicher, dass die Timereinstellungen so stimmen.

Noch etwas seltsames ist mir aufgefallen.
Wenn ich als Anfangszustand PD5 auf "0" setze, geht die LED trotzdem an, 
dh. die if-Abfrage in der ISR wird durchlaufen.
Wenn ich die Vergleichszahl in der if-abfrage jedoch ändere, z.B, auf 
100, 10000 oder 100000, dann ändert sich nichts am Verhalten der LED. 
Sie leuchtet minimal schwächer als bei High auf dem Pin.

Vor lauter Verzweiflung habe ich die timertest.c in den Anhang gepackt 
und hoffe, dass jemand das bei sich kompiliert, auf einen Atmega32 mit 
16MHz-clock spielt und damit den Fehler reproduzieren oder ausschließen 
kann. :)

von Jochen Schemmel (Gast)


Lesenswert?

>Um das interpretieren zu können: Wie sind deine LED verschaltet?
>Leuchten die bei 0 am Port oder bei 1 am Port?
>
>(Bin von einer 1 am Port ausgegangen)

Die LED leuchten bei einer 1 am Pin.

von Peter (Gast)


Lesenswert?

Warum startest du das Programm nicht einfach mal im Simulator - genau 
für soetwas ist der ja da? Mache ein Breakpoint in der ISR und schau dir 
die Zeiten an.

von Michael W. (retikulum)


Lesenswert?

Entweder ist mein Datenblatt alt oder du hast dich vertan.
>TCCR0 = (1<<WGM01) | (1<<CS01) | (1<<CS00);   /*CTC, prescaler 64*/

ist ein Prescaler von 32. Aber das ist noch nicht die Ursache.

Michael

von Jochen Schemmel (Gast)


Lesenswert?

Peter schrieb:
>Warum startest du das Programm nicht einfach mal im Simulator - genau
>für soetwas ist der ja da? Mache ein Breakpoint in der ISR und schau dir
>die Zeiten an.

Bin gerade dabei. Leider habe ich nicht so viel Erfahrung mit dem 
Simulator. Im Processor-Fenster habe ich anstatt 16MHz nur 4MHz stehen. 
Ich gehe mal davon aus, dass dies eine Obergrenze für den Simulator 
darstellt. Die ISR wird ca. alle 4ms angesprungen, was bei 4MHz korrekt 
ist.
Die IRS wird angesprungen.
Ich habe mal die Variable count näher betrachtet. Im "watch"-Fenster 
ändert diese den Wert nur zwischen 0 und 1, anstatt bis 1000 
hochzuzählen. Weiterhin wird, wenn ich den Code automatisch durchlaufen 
lasse, jedesmal die If-Anweisung durchlaufen, statt bei nur bei 1000. 
Ist das ein Bedienfehler oder wie ist das zu deuten?


Michael W. schrieb:
>Entweder ist mein Datenblatt alt oder du hast dich vertan.
>>>TCCR0 = (1<<WGM01) | (1<<CS01) | (1<<CS00);   /*CTC, prescaler 64*/
>ist ein Prescaler von 32. Aber das ist noch nicht die Ursache.

Also auf dem Datenblatt des Atmega32 (S.82) gibt es keinen Faktor 32.

von Stefan E. (sternst)


Lesenswert?

1
  if(count==1000);
Semikolon entfernen.

von Karl H. (kbuchegg)


Lesenswert?

Jochen Schemmel schrieb:
> Peter schrieb:

> Ich habe mal die Variable count näher betrachtet. Im "watch"-Fenster
> ändert diese den Wert nur zwischen 0 und 1, anstatt bis 1000
> hochzuzählen. Weiterhin wird, wenn ich den Code automatisch durchlaufen

Ah. das war der entscheidende Hinweis.

ISR(TIMER0_COMP_vect)           /*wird jede Millisekunde angesprungen*/
{
  count++;
  if(count==1000);                              /*nach einer Sekunde*/
  {


Siehst du den kleinen ; nach der schliessenden Klammer :-)

von Oliver (Gast)


Lesenswert?

>Weiterhin wird, wenn ich den Code automatisch durchlaufen
>lasse, jedesmal die If-Anweisung durchlaufen, statt bei nur bei 1000.
>Ist das ein Bedienfehler oder wie ist das zu deuten?

Ein ganz genauer Blick auf das Zeilenende mag die Erklärung dafür 
liefern :-)

1
 if(count==1000);

Oliver

von Peter (Gast)


Lesenswert?

> Bin gerade dabei. Leider habe ich nicht so viel Erfahrung mit dem
> Simulator. Im Processor-Fenster habe ich anstatt 16MHz nur 4MHz stehen.
> Ich gehe mal davon aus, dass dies eine Obergrenze für den Simulator
> darstellt. Die ISR wird ca. alle 4ms angesprungen, was bei 4MHz korrekt
> ist.
Da es eh kein Echtzeit Simulator ist, sind die 4 Mhz eh nur zur 
berechnung der Zeit. Du kannst aber auch jede andere Mhz bei den 
Optionen für die Simulator instellen.

von Jochen Schemmel (Gast)


Lesenswert?

AHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHRG!!!!

Ich habe den Fehler gefunden!
1
ISR(TIMER0_COMP_vect)
2
{
3
  static volatile unsigned int count;
4
  count++;
5
  if(count==1000); <========================== Semikolon zuviel!!!!
6
  {
7
    PORTD^=(1<<PD5);                                  
8
    count=0;
9
  }
10
}

Wenn das Semikolon weg ist, dann klappt das Prima mit dem Code!

Vielen Dank für die Hilfestellungen.
Ich bitte um Entschuldigung für die Zeit die ich euch mit diesem 
dämlichen Fehler geraubt habe.

Also, nun bin ich bereit schläge zu Empfangen! Schlagt mich, aber bitte 
einer nach dem anderen!

von Jochen Schemmel (Gast)


Lesenswert?

Ihr hab ihn auch gefunden :)

von Karl H. (kbuchegg)


Lesenswert?

Jochen Schemmel schrieb:
> Ihr hab ihn auch gefunden :)

Das ist nicht so wichtig.

Wichtig ist, dass du ihn gefunden hast und auch, dass dir im Simulator 
aufgefallen ist, dass hier anscheinend etwas nicht stimmt: Der Block 
unter dem if war anscheinend nicht vom if abhängig. Das ist der 
entscheidende Hinweis auf dieses spezifische 'Problem'. Wenn du beim 
nächsten mal im Simulator dieselben Symptome siehst, wirst du dich daran 
erinnern und sofort das Zeilenende beim if nach einem ; absuchen :-)

So lernt man.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Außerdem könntest du mal einen Blick auf Compilerwarnungen werfen.
Wenn ich mir deinen Schnipsel mit -Wall -Wextra compiliere, dann
bekomme ich:
1
foo.c: In function '__vector_10':
2
foo.c:30: warning: empty body in an if-statement

von Peter (Gast)


Lesenswert?

genau aus dem grund gehört bei mir die { auf die Zeile von dem if

if (a==1); {
   mach was;
}


if (a==1);
{
   mach was;
}


bei der ersten Variante sieht man gleich das das was nicht stimmt. Und 
es passen auch mehr Zeilen auf den Bildschirm

von Jochen Schemmel (Gast)


Lesenswert?

Dieser peinliche Fehler hat einen AHA-Effekt bei mir ausgelöst. Davon 
abgesehen, dass ich ihn nieee wieder machen werde, habe ich in den 
Stunden(!!!) der Verzweiflung, vor allem bei der Fehlersuche und das 
Drumherum sehr viel dazugelernt.

Ich werde mich auf jeden Fall mehr mit dem Simulator beschäftigen.

Jörg Wunsch schrieb:
>Außerdem könntest du mal einen Blick auf Compilerwarnungen werfen.
>Wenn ich mir deinen Schnipsel mit -Wall -Wextra compiliere, dann
>bekomme ich:
>
>foo.c: In function '__vector_10':
>foo.c:30: warning: empty body in an if-statement

Ich dachte das standardmäßig mit -Wall (Warning->all?) die stärkste 
Warningstufe eingestellt ist. Wusste nicht das es noch die Option 
-Wextra gibt. Ich habe sie bei CUSTOM OPTIONS unter CONFIGURATION 
OPTIONS eingetragen und einige andere meiner Test-Projekte compiliert. 
Und siehe da: aus 0 Warnings, 0 Fehler wurden auf einmal 4 Warnings, 0 
Fehler. Z.B.

warning: comparison between signed and unsigned

Auch wenn es in diesem Fall keine Auswirkungen auf das Programm hatte, 
so lernt man sauberer zu programmieren.

Peter schrieb:
>genau aus dem grund gehört bei mir die { auf die Zeile von dem if
>
>if (a==1); {
>   mach was;
>}
>
>
>if (a==1);
>{
>   mach was;
>}
Kurze Anekdote dazu:
Ich hatte einen Informatiklehrer, der hat uns mit der Todesstrafe 
gedroht,  falls wir es wagen sollten, die öffnende geschweifte Klammer 
eines Blocks in die gleiche Zeile wie den Befehl zu schreiben. :)

Danke nochmals an alle für die super Tipps, Erfahrung ist wirklich durch 
nichts zu ersetzen!

MFG

Jochen

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.