Forum: Mikrocontroller und Digitale Elektronik Atmega8 - IF-Schleife wird ignoriert


von Nico H. (gecko2152)


Lesenswert?

Hallo,
Seit einiger Zeit beschäfftige ich mich jetzt schon mit µControllern 
aber jetzt steh ich vor einem Problem, wo ich einfach nicht weiter weiß.

Ich habe unter AVR ein Beispiel Code geschrieben und simuliert um zu 
schauen ob es funktioniert: hier mal ein auszug.

#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>
#include <avr/interrupt.h>
#include <avr/iom8.h>

uint8_t zaehler0=0,start=0,status=0,status1=0,zahl=0;

int main(void)
{
  DDRD |=  (1<<PD7);

  //Timer0 starten
  TCCR0 |= (1<<CS02)|(1<<CS00);  //Vorteiler gleich 1024 (Timer0)
  TIMSK |= (1<<TOIE0);      //Interrupt an --> kommt alle 65,5 ms

  sei();    //Interrupts ein

  while(1)
  {
      //Zählschleife
      if (zaehler0>=4)   //wenn der Zähler mind 4 mal einen Overflow
      {          //erzeugt (250ms) hat soll diese Schleife ausgeführt 
werden
        //Testfkt --> LED an und aus
        if (start==1)
        {
          PORTD |= (1<<PD7);
          start=0;
        }
        else
        {
          PORTD &=~ (1<<PD7);
          start=1;
        }
        zahl=0;//Rücksetzen des Zählers
      }
  }

return(0);
}

ISR(TIMER0_OVF_vect)  //Interrupt Timer0 alle 65.5 ms
{
  zahl++;
  //if (zahl>=4)
  //{ zahl=0;}
}

Und jetzt kommt der Knackpunkt
Die Zahl wird brav hochgezählt doch in der While-Schleife springt das 
Programm nie in die If-Anweisung obwohl die Variable schon längst 4 oder 
größer erreicht hat.

Bei einem anderen Projekt mit einem Atmega32 hab ich den selben 
Programmcode verwendet um eine Led zum blinken zu bringen und dort hat 
es wunderbar funktioniert und nun nicht mehr.

Kennt einer dieses Problem oder eine Ahnung woran es liegen kann?

Ich hab auch schon ausbrobiert unabhängig vom Timer einfach in der while 
schleife ne variable hochzählen zu lassen, aber selbst das macht er 
nicht.

von Karl H. (kbuchegg)


Lesenswert?

Nico H. schrieb:

> Die Zahl wird brav hochgezählt doch in der While-Schleife springt das
> Programm nie in die If-Anweisung obwohl die Variable schon längst 4 oder
> größer erreicht hat.

Kann ich mir nicht vorstellen.
Du zählst die Variable 'zahl' hoch.
Abfragen tust du aber die Variable 'zaehler0'

PS: zahl musst du als volatile definieren.
1
volatile uint8_t zahl;

> Bei einem anderen Projekt mit einem Atmega32 hab ich den selben
> Programmcode verwendet um eine Led zum blinken zu bringen und dort hat
> es wunderbar funktioniert und nun nicht mehr.

Das ist die Krux, wenn man einfach Code von einem Projekt in ein anderes 
umkopiert: Du musst dir immer ansehen, welche Variablen wie verwendet 
werden und ob das alles zusammenpasst.
Ganz einfach nur die Variablen nachdefinieren, die der Compiler 
anmeckert ist zuwenig.

von Justus S. (jussa)


Lesenswert?

Nico H. schrieb:

> Bei einem anderen Projekt mit einem Atmega32 hab ich den selben
> Programmcode verwendet um eine Led zum blinken zu bringen und dort hat
> es wunderbar funktioniert

unwahrscheinlich..du zählst zahl hoch und fragst zaehler0 ab...

von Stefan E. (sternst)


Lesenswert?

1.
Du erhöhst im Interrupt zahl, testest in der Schleife aber zaehler0.

2.
volatile

von Oliver (Gast)


Lesenswert?

Nun ja, in der ISR zahl++ zu schreiben, und dann auf if (zaehler0>=4) zu 
prüfen, ist irgendwie wenig sinnvoll.

Als nächstes fehlt dann da ein volatile.

Und
>#include <avr/iom8.h>
ist überflüssig.

Oliver

von Nico H. (gecko2152)


Lesenswert?

ach ups das hatte ich noch nicht wieder geändert

hab da soviel rumgespielt das ich das wieder vergessen hab zurück zu 
ändern also der Code nochmal so wie er auch sein soll, aber trotzdem net 
funzt

#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>
#include <avr/interrupt.h>
#include <avr/iom8.h>

uint8_t zaehler0=0,start=0,status=0,status1=0,zahl=0;

int main(void)
{
  DDRD |=  (1<<PD7);

  //Timer0 starten
  TCCR0 |= (1<<CS02)|(1<<CS00);  //Vorteiler gleich 1024 (Timer0)
  TIMSK |= (1<<TOIE0);      //Interrupt an --> kommt alle 65,5 ms

  sei();    //Interrupts ein

  while(1)
  {
      //Zählschleife
      if (zaehler0>=4)   //wenn der Zähler mind 4 mal einen Overflow
      {          //erzeugt (250ms) hat soll diese Schleife ausgeführt
werden
        //Testfkt --> LED an und aus
        if (start==1)
        {
          PORTD |= (1<<PD7);
          start=0;
        }
        else
        {
          PORTD &=~ (1<<PD7);
          start=1;
        }
        zaehler0=0;//Rücksetzen des Zählers
      }
  }

return(0);
}

ISR(TIMER0_OVF_vect)  //Interrupt Timer0 alle 65.5 ms
{
  zaehler0++;
  //if (zahl>=4)
  //{ zahl=0;}
}


Nachtrag: Jetzt hab ich aber das mit dem volatile ausprobiert und auf 
einmal funzt es, aber wie kann es sein das ich hier volatile benutzen 
muß und ich damlas beim atmega32 das nicht braucht?

von Justus S. (jussa)


Lesenswert?

volatile fehlt immer noch und zurücksetzen solltest du auch zaehler0 und 
nicht zahl...

von Karl H. (kbuchegg)


Lesenswert?

Nico H. schrieb:

> Nachtrag: Jetzt hab ich aber das mit dem volatile ausprobiert und auf
> einmal funzt es, aber wie kann es sein das ich hier volatile benutzen
> muß und ich damlas beim atmega32 das nicht braucht?

Das kann daher kommen, das dein Programm am atmega32 damals anders 
ausgesehen hat und der Optimizer keine Chance hatte, die betreffénde 
Variable in einem CPU Register vorrätig zu halten, so dass er bei der 
nächsten Abfrage nicht erst den Wert langsam aus dem SRAM holen musste, 
sondern schnell aus einem Register holen konnte.

Denn genau das macht volatile: Es teilt dem Compiler mit, dass sich eine 
Variable auf Wegen ändern kann, die der Compiler naturbedingt bei einer 
Datenflussanalyse nicht erkennen kann und er daher auch tatsächlich auch 
immer auf die Variable zugreifen soll, wenn du in deinem Code einen 
Zugriff programmierst. Ist eine Variable nicht volatile, dann versucht 
der Compiler, Zugriffe aufs SRAM zu vermeiden, indem er zb davon 
ausgeht, dass sich eine Variable zwischen 2 Codestellen, zwischen denen 
die Variable seiner Meinung nach nicht verändert wird, in der CPU in 
einem Register vorrätig zu halten. Dumm nur, wenn eine ISR 
dazwischenhaut und die Variable im SRAM ändert, der Abfragecode aber 
nichts davon weiß und mit dem im CPU Register-Cache vorrätig gehaltenen 
Wert weiterrechnet.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

<Pedanterie>

Es gibt keine "if-Schleifen".

Schreib' das jetzt mindestens sooft, wie Deine "if-Schleife" nicht 
durchlaufen wird.

</Pedanterie>

von Nico H. (gecko2152)


Lesenswert?

tschuldige meinte natürlich if-anweisung

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.