Forum: Mikrocontroller und Digitale Elektronik if-Abfrage in C macht Probleme


von Toni (Gast)


Lesenswert?

Hallo,

ich bin kurz vor dem Verzweifeln. Atmega 8 funktioniert auf meiner 
Schaltung und Timer2 wird verwendet um eine PWM-Modulation zu 
simulieren, die durch einen RC-Tiefpass geglättet wird (benötige 
einstellbare Gleichspannung). Die Variable SignalOVFL wird in der ISR 
einfach auf 1 gesetzt.
Mein Problem besteht darin, dass ich in der while(1) Schleife nicht in 
die 2. If-Abfrage hinein komme. Ändere ich die Variable "status" auf 1 
(so wie im Code unten), komme ich in die obere If-Abfrage nicht hinein.
Kann mir einer sagen warum? Selbst im Debugger funktioniert es, nur 
nicht auf meiner Schaltung...
Danke schonmal für eure Tipps.
1
/* Globale Variablen */
2
//Timer2
3
volatile uint8_t SignalOVFL = 0;
4
volatile uint8_t status = 1;
5
6
/* MAIN */
7
void main (void)
8
{
9
  timer_kontrast();// Timer 2 initalisieren und starten
10
    
11
  while(1)
12
  {    
13
    if(SignalOVFL == 1 && status == 0)
14
    {
15
      //PORTB ^= (1<<PB2);    // Pin einschalten
16
      SignalOVFL = 0;      // Interrupt Rücksetzen
17
      status = 1;          // Für nächsten Durchgang status = setzen
18
    }
19
    if(SignalOVFL == 1 && status != 0)
20
    {
21
      PORTB ^= (1<<PB2);    // Pin ausschalten
22
      SignalOVFL = 0;      // Interrupt Rücksetzen
23
      status = 0;          // Für nächsten Durchgang status = löschen
24
      //TCNT2 = 0;      // Timerregister vorladen
25
    }
26
  }

von Da D. (dieter)


Lesenswert?

Der Fehler liegt in Zeile 42. Die ist in deinem Beispiel leider nicht zu 
sehen.

von Rene (Gast)


Lesenswert?

Der Code fehlt wo SignalOVFL und status manipuliert werden. Deshalb kann 
Dir so keiner sagen wo das Problem ist.

Mit dem Codesausschnitt dürfte er in gar keinen if-Block reinkommen.

von Klammeraffe (Gast)


Lesenswert?

Toni schrieb:
> if(SignalOVFL == 1 && status == 0)

Bin mir nicht sicher wie die Reichenfolge der Operatoren ausgewertet 
wird. Versuch mal:

if((SignalOVFL == 1) && (status == 0))

von Toni (Gast)


Lesenswert?

Häh?

Welchen Code benötigst du noch? Timer und ISR funktionieren, es geht im 
Grunde nur um die status-Variable.
1
void timer_kontrast() //Ausgabe der Frequenz auf PB2 // Timer 2 wird verwendet
2
{
3
  // Ausgang Pin PB2 auf Ausgang setzen
4
  DDRB |= (1<<DDB2);
5
  
6
  //Interrupts aktivieren
7
  TIMSK |= (1<<OCIE2) | (1<<TOIE2);
8
  
9
  //Timer starten; Prescaler = 256
10
  TCCR2 |= (1<<CS22);
11
  sei();
12
}
13
14
ISR(TIMER2_OVF_vect)  //Timer2 OVERFLOW Vector 5
15
{
16
  SignalOVFL = 1;
17
}

von Peter II (Gast)


Lesenswert?

der code sieht richtig aus, und wenn er im debugger funktioniert dann 
ist er auch richtig. Also wird das problem wohl mehr an der hardware 
liegen.

von STK500-Besitzer (Gast)


Lesenswert?

Klammeraffe schrieb:
> if((SignalOVFL == 1) && (status == 0))

sieht besser aus.

1
  {    
2
    if(SignalOVFL == 1)
3
    {
4
     if (status == 0)
5
     {
6
       //PORTB ^= (1<<PB2);    // Pin einschalten
7
       SignalOVFL = 0;      // Interrupt Rücksetzen
8
       status = 1;          // Für nächsten Durchgang status = setzen
9
      }
10
      else
11
      {
12
       PORTB ^= (1<<PB2);    // Pin ausschalten
13
       SignalOVFL = 0;      // Interrupt Rücksetzen
14
       status = 0;          // Für nächsten Durchgang status = löschen
15
      //TCNT2 = 0;      // Timerregister vorladen
16
      }
17
    }

dürfte schneller sein (und funktionieren)...

von Uwe (de0508)


Lesenswert?

Toni pampig ?

wenn man den Code im ersten Post durchdenkt, sieht man, dass beide 
If-Zweige immer Falsch (FALSE) sind. Deshalb sein Nachfragen.

Wenn Du Hilfe suchst musst Du IMMER ALLES hier veröffentlichen,
sonst erhälst Du eine "42" als Fehlergrund.

Raten ist nun mal schwierig.

von Leser (Gast)


Lesenswert?

Klammeraffe schrieb:
> Bin mir nicht sicher wie die Reichenfolge der Operatoren ausgewertet
> wird.

Soetwas kann man zum Glück nachlesen ;-)
http://de.wikibooks.org/wiki/C-Programmierung:_Liste_der_Operatoren_nach_Priorit%C3%A4t

von Peter II (Gast)


Lesenswert?

STK500-Besitzer schrieb:
> sieht besser aus.
>
>   {
>     if(SignalOVFL == 1)
>     {
>      if (status == 0)
>      {
>        //PORTB ^= (1<<PB2);    // Pin einschalten
>        SignalOVFL = 0;      // Interrupt Rücksetzen
>        status = 1;          // Für nächsten Durchgang status = setzen
>       }
>       else
>       {
>        PORTB ^= (1<<PB2);    // Pin ausschalten
>        SignalOVFL = 0;      // Interrupt Rücksetzen
>        status = 0;          // Für nächsten Durchgang status = löschen
>       //TCNT2 = 0;      // Timerregister vorladen
>       }
>     }
>
>
> dürfte schneller sein (und funktionieren)...

naja, wenn man schon optimiert dann aber richitg. Es gibt noch gleihen 
code in if und else.

Aber die alte version war auch nicht falsch.

von Hagan (Gast)


Lesenswert?

STK500-Besitzer schrieb:
> Klammeraffe schrieb:
>> if((SignalOVFL == 1) && (status == 0))
>
> sieht besser aus.

Dem stimme ich zu.

>
1
>   {
2
>     if(SignalOVFL == 1)
3
>     {
4
>      if (status == 0)
5
>      {
6
>        //PORTB ^= (1<<PB2);    // Pin einschalten
7
>        SignalOVFL = 0;      // Interrupt Rücksetzen
8
>        status = 1;          // Für nächsten Durchgang status = setzen
9
>       }
10
>       else
11
>       {
12
>        PORTB ^= (1<<PB2);    // Pin ausschalten
13
>        SignalOVFL = 0;      // Interrupt Rücksetzen
14
>        status = 0;          // Für nächsten Durchgang status = löschen
15
>       //TCNT2 = 0;      // Timerregister vorladen
16
>       }
17
>     }
18
> 
19
>
>
> dürfte schneller sein (und funktionieren)...

Warum schneller? Warum funktionieren?

von Toni (Gast)


Lesenswert?

Nein, nicht Toni pampig. Hab extra geschrieben, dass die Variable in der 
ISR auf 1 gesetzt wird. Wollte euch eben etwas Denk-arbeit abnehmen. 
Sorry.
Tipps von Klammeraffe und STK-500 Besitzer getestet, ohne Erfolg. In 
eine If-Schleife kommt er nicht rein, egal wie ich es biege und 
beklammere. PWM-Signal liegt auf dem Pin-Ausgang an, allerdings nur, 
wenn man die richtige Schleife ausklammert... Ich verstehe es nicht.

von Klammeraffe (Gast)


Lesenswert?

Leser schrieb:
>> Bin mir nicht sicher wie die Reichenfolge der Operatoren ausgewertet
>> wird.
>
> Soetwas kann man zum Glück nachlesen ;-)
> http://de.wikibooks.org/wiki/C-Programmierung:_Lis...

Danke für den Link.
Na, dann ist das ja schonmal geklärt.

von Hagan (Gast)


Lesenswert?

> Ich verstehe es nicht.

Wenn du nicht alle Informationen auf den Tisch legst, dann ich auch 
nicht.

von Karl H. (kbuchegg)


Lesenswert?

Toni schrieb:

> Mein Problem besteht darin, dass ich in der while(1) Schleife nicht in
> die 2. If-Abfrage hinein komme. Ändere ich die Variable "status" auf 1
> (so wie im Code unten), komme ich in die obere If-Abfrage nicht hinein.
> Kann mir einer sagen warum?

Da ist irgendwas faul, was du nicht gezeigt hast.

Aber:
So wie ich das sehe, ist die Absicht hinter dem Code, den Pin bei jedem 
Timer-Overflow umzuschalten. Oder bei jedem 2.ten Timer-Overflow? Doch, 
ich denke du willst jeden 2.ten Timer Overfow.


Da frag ich mich, warum du das so komplizert mit 3 Millionen 
zusätzlichen Variablen machst.
1
ISR( .... )
2
{
3
  static int isrCount = 0;
4
5
  isrCount++;
6
  if( isrCount == 2 ) {
7
    PORTB ^= (1<<PB2);
8
    isrCount = 0;
9
  }
10
}

und gut ists. Die ganze komplizierte Steuerung über OverflowFlags und 
signal Flag braucht doch (zumindest in dem Teil den du gezeigt hast) in 
Wirklichkeit keiner (auch wenn ich im gezeigten Abschnitt nichts sehen 
kann, was deine Beobachtung erklären würde - vergreifst du dich an 
anderer Stelle im Code ebenfalls am PORTB? Da könnte zb auch ein Fehler 
stecken)

von Thomas E. (thomase)


Lesenswert?

Peter II schrieb:
> naja, wenn man schon optimiert dann aber richitg. Es gibt noch gleihen
> code in if und else.
1
if(SignalOVFL)
2
{
3
  if(status) PINB |= (1<<PB2);
4
  status = !status;
5
  SignalOVFL = 0;
6
}

mfg.

von Toni (Gast)


Lesenswert?

Danke Karl Heinz,

du liegst nicht ganz Falsch. Ich benötige im Grunde eine PWM-Modulation 
und möchte dementsprechend in einer der beiden Schleifen das 
Zählregister mit einem Wert vorladen, sodass Einschalt - und 
Ausschaltdauer unterschiedlich sind. Die entsprechenden Pins für die 
PWM-modi stehen nicht zur Verfügung, deswegen möchte ich das ganze ein 
Stück weit per Software abarbeiten.

von Ingo (Gast)


Lesenswert?

Darf man fragen woran du erkennst das die Bedingung nicht erfüllt wird?

von Karl H. (kbuchegg)


Lesenswert?

Toni schrieb:

> In
> eine If-Schleife

es gibt keine if-Schleife.

Eine Schleife ist dem Wesen nach ein Code-Element, in dem anderer Code 
wiederholt ausgeführt wird. Drum heißt es Schleife.

Macht ein if dieses?
Nein.
Also ist ein if keine Schleife.

> kommt er nicht rein, egal wie ich es biege und
> beklammere. PWM-Signal liegt auf dem Pin-Ausgang an, allerdings nur,
> wenn man die richtige Schleife ausklammert...

D.h. du machst das daran fest, dass du nichts am Ausgang siehst?

Ok. HJast du den Pin auch auf Ausgang gestellt?
Vergreifst du dich sonst irgendwo am PORTB?

> Ich verstehe es nicht.

Wenn du endlich deinen kompletten verdammten Code zeigen würdest, dann 
hätte man das Problem in 3 Minuten gelöst. Aber du weigerst dich ja.

von Karl H. (kbuchegg)


Lesenswert?

Toni schrieb:

> du liegst nicht ganz Falsch. Ich benötige im Grunde eine PWM-Modulation
> und möchte dementsprechend in einer der beiden Schleifen das
> Zählregister mit einem Wert vorladen, sodass Einschalt - und
> Ausschaltdauer unterschiedlich sind.

Und?
Das kann man nicht in der ISR erledigen, oder wie?

von Toni (Gast)


Lesenswert?

So, nachmal etwas ausprobiert, dass gleiche in Grün...
Nochmal; Das ist der komplette Code, mehr gibt es nicht.
Kann es sein, dass die Variable Status durch die Optimierung 
wegoptimiert wird?! Das sollte doch eigentlich volatile verhindern, 
oder?
Die auskommentierten Code-Schnipsel sind Verzweiflungsmaßnahmen, also 
bitte nicht beachten.
1
// Definitionen
2
#define F_CPU 2000000
3
4
// INCLUDE
5
#include <avr/io.h>
6
#include <avr/interrupt.h>
7
#include <util/delay.h>
8
#include <stdint.h>
9
10
/* Globale Variablen */
11
//Timer2
12
volatile uint8_t status = 0;
13
14
/* MAIN */
15
void main (void)
16
{
17
  timer_kontrast();
18
    
19
  while(1);
20
}
21
22
void timer_kontrast() //Ausgabe der Frequenz auf PB2 // Timer 2 wird verwendet
23
{
24
  // Ausgang Pin PB2 auf Ausgang setzen
25
  DDRB |= (1<<DDB2);
26
  
27
  //Interrupts aktivieren
28
  TIMSK |= (1<<OCIE2) | (1<<TOIE2);
29
  //TIFR = (1<<OCF2) | (1<<TOV2);
30
  
31
  //Timer starten; Prescaler = 256
32
  TCCR2 |= (1<<CS22);
33
  sei();
34
}
35
36
ISR(TIMER2_OVF_vect)  //Timer2 OVERFLOW Vector 5
37
{
38
  //PORTB ^= (1<<PB2);
39
  //uint8_t tmp_sreg;
40
  //tmp_sreg = SREG;
41
  
42
  if(status == 0)
43
  {
44
    PORTB ^= (1<<PB2);
45
    status = 1;
46
  }
47
  if(status == 1)
48
  {
49
    //PORTB ^= (1<<PB2);
50
    status = 0;
51
  }
52
  
53
  //SREG = tmp_sreg;
54
}

von J.-u. G. (juwe)


Lesenswert?

Ich schließe mich der Frage von Ingo an:

> Darf man fragen woran du erkennst das die Bedingung nicht erfüllt wird?

von Karl H. (kbuchegg)


Lesenswert?

Toni schrieb:

> Das ist der komplette Code, mehr gibt es nicht.
Na das ist doch mal ein Wort.

>   TIMSK |= (1<<OCIE2) | (1<<TOIE2);

Du gibst einen Interrupt frei, für den du keinen ISR-Handler hast
-> µC wird resettet


Sonst noch was, womit du nicht weiter kommst?
Vielleicht verstehst du jetzt, warum wir lieber den kompletten Code 
sehen anstelle von immer nur ein paar Ausschnitten.
1 Stunde Diskussion, damit du endlich den kompletten Code zeigst und 
dann kann das Problem in ein paar Minuten in dem Codeteil gefunden 
werden, den du eben nicht gezeigt hast.

von Rene (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Wenn du endlich deinen kompletten verdammten Code zeigen würdest, dann
> hätte man das Problem in 3 Minuten gelöst. Aber du weigerst dich ja.

Karl Heinz Buchegger schrieb:
> Du gibst einen Interrupt frei, für den du keinen ISR-Handler hast
> -> µC wird resettet

Das hat mal Stil. Gesagt und getan. Und in der Tat in exakt 3 Minuten. 
:-)
Ich bin beeindruckt.

Grüsse,
René

von Toni (Gast)


Lesenswert?

> Darf man fragen woran du erkennst das die Bedingung nicht erfüllt wird?

Anhand eines an dem Pin angeschlossenem Oszis, dass mir ein PWM-Signal 
anzeigt, sobald sich der µC in der entsprechenden Verzweigung befindet. 
Ansonsten liegen konstante 0V an dem Ausgang an. Zusätlich liefert mir 
ein Multimeter 2,5V bzw. 0V. Deshalb klammere ich den toggelnden Pin 
entsprechend der Verzweigung aus. Aus diesem Grund nehme ich an, dass 
Timer, ISR und co funktioniert, allerdings ein Problem mit der 
Verzweigung besteht.

von Toni (Gast)


Lesenswert?

Problem ist leider nicht gelöst!!!

von Rene (Gast)


Lesenswert?

Toni schrieb:
> if(status == 0)
>   {
>     PORTB ^= (1<<PB2);
>     status = 1;
>   }
>   if(status == 1)
>   {
>     //PORTB ^= (1<<PB2);
>     status = 0;
>   }

Das geht so nicht. Dein Status hat so immer 0.

Wenn, dann musst Du:
1
  if(status == 0)
2
  {
3
    PORTB ^= (1<<PB2);
4
    status = 1;
5
  }
6
  if(status == 1)
7
  {
8
    //PORTB ^= (1<<PB2);
9
    status = 0;
10
  }

Grüsse,
R.

von STK500-Besitzer (Gast)


Lesenswert?

Peter II schrieb:
> naja, wenn man schon optimiert dann aber richitg. Es gibt noch gleihen
> code in if und else.


Weniger Abfragen. Die Zuweisungen habe ich mir nicht näher angesehen.

Rene schrieb:
> if(status == 0)
>   {
>     PORTB ^= (1<<PB2);
>     status = 1;
>   }
>   if(status == 1)
>   {
>     //PORTB ^= (1<<PB2);
>     status = 0;
>   }


Wo ist da der Unterschied zum vorherigen Code?
Schon mal was von "else" gehört (nein, ich meine nicht "Else" aus 
DOS-Zeiten ;)

von Rene H. (Gast)


Lesenswert?

Ja, das wollte ich in meinem Post korrigieren, was in einem Desaster 
geendet hat (copy & paste will beherrscht werden). Karl Heinz ist schon 
informiert. Sorry deswegen.

Also:
1
  if(status == 0)
2
  {
3
    PORTB ^= (1<<PB2);
4
    status = 1;
5
  }
6
  else if(status == 1)
7
  {
8
    //PORTB ^= (1<<PB2);
9
    status = 0;
10
  }

Grüsse,
R.

Beim ersten if Block setzt Du status = 1. Danach wird aber sofort Dein 
zweiter if Block ausgeführt und der Status auf 0 zurück gesetzt. Du 
musst also ein else dazwischen hängen.

von Peter II (Gast)


Lesenswert?

Rene H. schrieb:
> a, das wollte ich in meinem Post korrigieren, was in einem Desaster
> geendet hat (copy & paste will beherrscht werden). Karl Heinz ist schon
> informiert. Sorry deswegen.
>
> Also:
>   if(status == 0)
>   {
>     PORTB ^= (1<<PB2);
>     status = 1;
>   }
>   else if(status == 1)
>   {
>     //PORTB ^= (1<<PB2);
>     status = 0;
>   }
>
> Grüsse,
> R.

na das ist nun auch nicht das gelbe vom ei.
1
   if(status == 0)
2
   {
3
     PORTB ^= (1<<PB2);
4
     status = 1;
5
   } else 
6
   {
7
     //PORTB ^= (1<<PB2);
8
     status = 0;
9
   }

von Toni (Gast)


Angehängte Dateien:

Lesenswert?

Super Leute, vielen Dank. Endlich funktioniert der Code.
Im Bild ist das Ergebnis zu sehen.
Warum es im ersten Fall nicht funktioniert hat, ist mir immernoch 
schleierhaft. Ich werde morgen nochmal ein bisschen herumprobieren.

Und hier noch die Änderungen:
1
ISR(TIMER2_OVF_vect)  //Timer2 OVERFLOW Vector 5
2
{
3
  //PORTB ^= (1<<PB2);
4
  //uint8_t tmp_sreg;
5
  //tmp_sreg = SREG;
6
  
7
  if(status == 0)
8
  {
9
    PORTB |= (1<<PB2);
10
    status = 1;
11
    TCNT2 = 200;
12
  }
13
  else
14
  {
15
    PORTB &= ~(1<<PB2);
16
    status = 0;
17
  }
18
  
19
  //SREG = tmp_sreg;
20
}

von Rene H. (Gast)


Lesenswert?

Sauber! Danke fürs Feedback.

Grüsse,
R.

von Toni (Gast)


Lesenswert?

Hi,

vollständigkeitshalber und für die Nachwelt hier noch der entsprechende 
Code mit schlanker ISR.
Hier schon etwas weiter mit zweitem Timer0.
Kann man die ISR ohne das sichern des SREG-Registers so stehen lassen?
1
// Definitionen
2
#define F_CPU 2000000
3
4
// INCLUDE
5
#include <avr/io.h>
6
#include <avr/interrupt.h>
7
#include <util/delay.h>
8
#include <stdint.h>
9
10
/**************************** Globale Variablen ****************************************/
11
//Timer2
12
volatile uint8_t InterruptAktivT2 = 0, StatusKontrast = 0;
13
//Timer0
14
volatile uint8_t InterruptAktivT0 = 0, StatusHelligkeit = 0;
15
/*************************************** MAIN *****************************************************/
16
void main (void)
17
{
18
  timer_kontrast();
19
  timer_helligkeit();
20
  
21
  while(1)
22
  {
23
    //Kontrast
24
    if(InterruptAktivT2 == 1)
25
    {
26
      //PB2 Einschalten
27
      if(StatusKontrast == 0)
28
      {
29
        PORTB |= (1<<PB2);
30
        StatusKontrast = 1;
31
        InterruptAktivT2 = 0;
32
        TCNT2 = 0;    // Register vorladen um Verhältnis einzustellen ***(0-255)*** 0 =>0,43V 255 =>0.85V am KontrastPin
33
      }
34
      //PB2 Ausschalten
35
      else
36
      {
37
        PORTB &= ~(1<<PB2);
38
        StatusKontrast = 0;
39
        InterruptAktivT2 = 0;
40
        //TCNT2 = 0;    // Wenn anderer Einstellbereich benötigt, hier vorladen
41
      }
42
    }
43
    
44
    //Helligkeit
45
    if(InterruptAktivT0 == 1)
46
    {
47
      //PB1 Einschalten
48
      if(StatusHelligkeit == 0)
49
      {
50
        PORTB |= (1<<PB1);
51
        StatusHelligkeit = 1;
52
        InterruptAktivT0 = 0;
53
        TCNT0 = 128;    // Register vorladen um Verhältnis einzustellen ***(0-250)*** 0 =>Hell 250 =>Dunkel
54
      }
55
      //PB1 Ausschalten
56
      else
57
      {
58
        PORTB &= ~(1<<PB1);
59
        StatusHelligkeit = 0;
60
        InterruptAktivT0 = 0;
61
      }
62
    }
63
  }// ende while
64
  
65
}// ende main
66
67
/************************************************** Funktionen *****************************************************/
68
69
void timer_kontrast() //Ausgabe der Frequenz auf PB2 // Timer 2 wird verwendet
70
{
71
  // Ausgang Pin PB2 auf Eingang setzen
72
  DDRB |= (1<<DDB2);
73
  
74
  //Interrupts aktivieren
75
  TIMSK |= (1<<TOIE2);
76
    
77
  //Timer starten; Prescaler = 8
78
  TCCR2 |= (1<<CS21);
79
  sei();
80
}
81
82
void timer_helligkeit() //Ausgabe der Frequenz auf PB1 // Timer 0 wird verwendet
83
{
84
  // Ausgang Pin PB1 auf Ausgang setzen
85
  DDRB |= (1 << DDB1);
86
      
87
  //Interrupts aktivieren
88
  TIMSK |= (1<<TOIE0);
89
      
90
  //Timer starten; Prescaler = 64
91
  TCCR0 |= (1<<CS01) | (1<<CS00);
92
  sei();
93
}
94
95
/************************************************ Interrupt routine ************************************************/
96
97
ISR(TIMER2_OVF_vect)  //Timer2 OVERFLOW Vector 5
98
{
99
  InterruptAktivT2 = 1;
100
}
101
102
ISR(TIMER0_OVF_vect)  //Timer0 OVERFLOW 
103
{
104
  InterruptAktivT0 = 1;
105
}

von STK500-Besitzer (Gast)


Lesenswert?

Toni schrieb:
> Kann man die ISR ohne das sichern des SREG-Registers so stehen lassen?

Ja, weil wir hie rnicht bei Assembler sind. DArum kümmert sich der 
Compiler.

Was soll das eigentlich werden?

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.