Forum: Mikrocontroller und Digitale Elektronik If Else geht nicht


von Ich D. (martaniu)


Lesenswert?

Wieso geht das nicht ?

while(1)

    {
    if (licht==1)
    {
      for(i=0;i<10000;i++)
      {
        PORTB=0b00111000;
        PORTC=0b00111111;
        PORTD=0b11100000;
        _delay_ms(2);
      }
    }
    if (licht==2)
    {
      for(i=0;i<10000;i++)
      {
        PORTB=0b00111000;
        PORTC=0b00111111;
        PORTD=0b11100000;
        _delay_us(750);

        PORTB=0b00000000;
        PORTC=0b00000000;
        PORTD=0b00000000;
        _delay_us(250);
      }
    }
    if (licht==3)
    {
      for(i=0;i<10000;i++)
      {
        PORTB=0b00111000;
        PORTC=0b00111111;
        PORTD=0b11100000;
        _delay_us(500);

        PORTB=0b00000000;
        PORTC=0b00000000;
        PORTD=0b00000000;
        _delay_us(500);
      }
    }
    if (licht==4)
    {
      for(i=0;i<10000;i++)
      {
        PORTB=0b00111000;
        PORTC=0b00111111;
        PORTD=0b11100000;
        _delay_us(250);

        PORTB=0b00000000;
        PORTC=0b00000000;
        PORTD=0b00000000;
        _delay_us(750);
      }
    }
    if (licht==5)
    {
      for(i=0;i<10000;i++)
      {
        PORTB=0b00000000;
        PORTC=0b00000000;
        PORTD=0b00000000;
        _delay_ms(1);
      }
    }
    if (licht==6)
    {
      licht=licht-6;
    }
    else if (licht==0)
    {
                    anderes geblinke
                }

Geschrieben auf einem Atmega8
Unten befindet sich eine interrupt routine welche den wert licht+1 macht 
wenn der Taster gedrückt wird
eigentlich sollte jetzt ja das Lich zuerst Hell und nach jedem Druck 
immer Dunkler werden

Danke schonmal im voraus
martaniu

von Paul Felz (Gast)


Lesenswert?

Fehlt da nicht ne Klammer?

von lalala (Gast)


Lesenswert?

- Taste nicht entprellt?
- Variable licht falsch initialisiert?
- Fall licht > 6 Fall nicht bearbeitet(der ja nicht auftreten sollte, 
aber ja vielleicht doch auftritt.

von Kaj (Gast)


Lesenswert?

Ich D. schrieb:
> if (licht==6)
>     {
>       licht=licht-6;
>     }
licht = 0

Ich D. schrieb:
> if (licht==6)
>     {
>       licht=licht-6;
>     }
>     else if (licht==0)
>     {
>                     anderes geblinke
>                 }
Wenn licht auf 0 gesetzt wurde (also vorher 6 war) dann kommt man 
natürlich, im selben durchlauf, nicht in den else zweig.

von Mein grosses V. (vorbild)


Lesenswert?

Ich D. schrieb:
> Wieso geht das nicht ?

Tolle Frage. Was geht nicht? Natürlich geht das. Es kommt nur nicht das 
raus, was du erwartest, oder?

Du wirst uns schon erzählen müssen, was das ist, was du erwartest.

von Klaus (Gast)


Lesenswert?

Was genau heisst: "Funktioniert nicht"? Siehe: 
https://www.mikrocontroller.net/articles/Netiquette

Wenn man Deinen Code ansieht, so hängt einzig die Dauer der Verzögerung 
von dem Wert der Variablen licht ab.

licht delay
1     2ms
2     750us
3     500us
4     250us
5     1ms
...

Alle anderen von der Bedingung abhängigen Vorgänge sind unabhängig vom 
Wert der Variablen licht gleich.

Daher ist es zu überlegen, ob Du nicht eine einzige Funktion schreibst, 
die ausschliesslich ein delay je nach ihrem Parameter ausführt. Das 
macht das Programm übersichtlicher.

Dazu kannst Du wieder eine Kette von if-Anweisungen benutzen oder eine 
switch-Anweisung.

z.B. so
1
void PerformDelay (int i) {
2
  if (licht==1)
3
    _delay_ms(750);
4
  else if (licht==2)
5
    _delay_ys(1);
6
  else if (licht==3)
7
    _delay_ms(500);
8
  else if (licht==4)
9
    _delay_ms(250);
10
  else if (licht==5)
11
    _delay_ms(1);
12
13
  // ...
14
  else
15
    // ...
16
}

Das ist eigentlich auch nur dann nötig, falls Du das delay das mit dem 
GCC für AVR kommt verwendest, weil dort das delay keine Variable als 
Parameter akzeptiert. Aber wir wissen ja auch nicht welcher uC oder 
welcher Compiler. Siehe 
https://www.mikrocontroller.net/articles/Netiquette
Lediglich die Benennung der Ports deutet darauf hin, dass es sich um 
einen AVR handeln könnte .

Das man Tasten wegen ihres Prellens nicht in Interrupt-Funktionen 
auswertet ist ja schon erwähnt worden.

von Klaus (Gast)


Lesenswert?

Ooops.

Die Bedingungen müssen natürlich nicht:

  if (licht==1)

sein, sondern

  if (i == 1)

was mich veranlasst, darauf hinzuweisen, das man für Variablennamen 
möglichst aussagekräftige verwendet. In diesem Sinne ist "licht" 
unzureichend - aber auch "i".

von Klaus (Gast)


Lesenswert?

Noch ein Ooops. Sorry.

Natürlich unterscheiden sich die abhängigen Anweisungen in noch mehr 
Punkten. Ich habe das - offen gesagt - ersteinmal aus Lässigkeit 
ignoriert. Dann schien es mir wahrscheinlicher, dass es sich um ein 
Versehen handelt. Aber das muss natürlich nicht zutreffen.

von Ich D. (martaniu)


Lesenswert?

Mein grosses V. schrieb:
> Ich D. schrieb:
>> Wieso geht das nicht ?
>
> Tolle Frage. Was geht nicht? Natürlich geht das. Es kommt nur nicht das
> raus, was du erwartest, oder?
>
> Du wirst uns schon erzählen müssen, was das ist, was du erwartest.

Ich wollte das wenn ich das erste mal den Taster drücke sich der 
komplette Würfel auf 100% Helligkeit anschaltet und beim 2.ten mal 
drücken auf 75% dimmt usw. am Ende soll er aus sein und nach nochmal 
drücken wieder in die Else-schleife springen.
Den Taster kann man benutzen da er Pull-up widerstände hat und auch in 
der Interroupt ein delay von 100ms ist.

von Ich D. (martaniu)


Lesenswert?

Jetzt geht es halbwegs...
Wenn ich am anfang meine variable (geändert auf g) auf 1 setze leuchtet 
der Würfel und das Dimmen funktioniert, wenn ich allerdings einmal durch 
bin mit dem Dimmen läuft der Rest einfach durch ohne das ich wieder 
Dimmen kann.

von Dieter F. (Gast)


Lesenswert?

Schau doch mal nach "switch case" ... das ist ein Klassiker dafür :-)

von Matthias L. (Gast)


Lesenswert?

1
if ( licht == ... )
2
{
3
  for(i=0;i<10000;i++)
4
  {
5
    ...
6
    _delay_ms(1);
7
  }
8
}
9
...

Das Problem deines Programmes ist das delay mit zehn Sekunden. Nur 
danach wird die Varaible Licht neu ausgewertet, selbst wenn diese durch 
irgendwas (Interrupt) mittlerweile mehrfach verändert wurde.

Du solltest das gesamte Konzept des Programmes umstellen. Offensichtlich 
willst Du verschiedene Bitmuster getimt an Ports ausgeben. Das kleinste 
Delay welches ich gesehen habe, ist 250µs. ALso baue einen Timertick mit 
250µs und schalte dort geeignet um.

Das hier macht noch nicht exakt was du wahrscheinlich willst, aber es 
sollte an Anreiz gehen:
1
uint_xx_t  WAIT[]   = ( ... , ... , ... , ... );
2
uint_xx_t  TimeTick = 0;
3
uint8_t    State    = 0;
4
5
main ( void )
6
{
7
  // init Timer ------------------------------
8
  ...
9
  //-- Main ----------------------------------
10
  while ( 1 )
11
  {
12
    asm volatile ( "nop" );
13
  }
14
}
15
16
ISR ( TIMER_x_OVF )  // alle 250µs
17
{
18
  //-- Variable Licht betüdeln ---------------
19
  uint_xx_t Max = (uint_xx_t) ( sizeof(WAIT) / sizeof(WAIT[0]) )
20
21
  if      ( ... ) Licht = 1;
22
  else if ( ... ) Licht = 2;
23
  ...
24
  if ( Licht >= Max ) Licht = 0;
25
26
  // Timing erzeugen -------------------------
27
  if ( ++TimeTick < WAIT[ Licht ] )  return;
28
  TimeTick = 0;
29
30
  // Ausgänge erzeugen -----------------------
31
  switch ( State )
32
  {
33
    case 0:
34
    {
35
      PORTB=0b00111000;
36
      PORTC=0b00111111;
37
      PORTD=0b11100000;
38
      State = 1;
39
      break;
40
    }
41
    case 1:
42
    {
43
      PORTB=0b00000000;
44
      PORTC=0b00000000;
45
      PORTD=0b00000000;
46
      State = 0;
47
      break;
48
    }
49
    default:
50
      State = 0;
51
  }
52
  //-- fertig --------------------------------
53
}

von Flip B. (frickelfreak)


Lesenswert?

Ich D. schrieb:
> in
> der Interroupt ein delay von 100ms ist.

very bad idea.

1. Versuche herauszufinden warum.
2. Bemühe dich, verständliche Grammatik anzuwenden.

von Mein grosses V. (vorbild)


Lesenswert?

Ich D. schrieb:
> Den Taster kann man benutzen da er Pull-up widerstände hat und auch in
> der Interroupt ein delay von 100ms ist.

Immerhin hast du 'widerstände' nicht mir 'ie' geschrieben. Das ist aber 
auch schon das einzig Gute.

Pull-Ups haben mit Entprellung gar nichts zu tun und ein Delay in der 
ISR ist nur in ganz wenigen Ausnahmefällen eine gute Idee. Bei einer 
nicht funktionierenden Entprellung ist es das allerdings nicht.

Einen Timer brauchst du sowieso. Damit und nur damit, kannst du das 
Entprellen gleich mit erledigen.

von Klaus R. (klara)


Lesenswert?

Ich D. schrieb:
> Wieso geht das nicht ?

Das Problem sitzt in der Regel vor dem Computer.
mfg klaus

von Ich D. (martaniu)


Lesenswert?

Ich entschuldige mich für meine Rechtschreibung ^^ bin noch in der 
Schule und nicht so häufig in Foren unterwegs.
Die Delays habe ich jetzt aus den if-schleifen genommen und es geht 
immmer noch so halbwegs Trottdem vielen Dank dafür das ihr mir schonmal 
soweit geholfen habt.
martaniu

von Walter S. (avatar)


Lesenswert?

Ich D. schrieb:
> if-schleifen

mit if-Schleifen ist man bei Programmierern sofort unten durch ;-)

von Walter S. (avatar)


Lesenswert?

Ich D. schrieb:
> wenn ich allerdings einmal durch
> bin mit dem Dimmen läuft der Rest einfach durch ohne das ich wieder
> Dimmen kann.

dann versuch mal die Antwort von Kaj zu lesen

von Klaus (Gast)


Lesenswert?

Ich D. schrieb:
> Ich entschuldige mich für meine Rechtschreibung ^^ bin noch in der
> Schule und nicht so häufig in Foren unterwegs.
> Die Delays habe ich jetzt aus den if-schleifen genommen und es geht
> immmer noch so halbwegs Trottdem vielen Dank dafür das ihr mir schonmal
> soweit geholfen habt.
> martaniu

Nun, wenn Du Schüler bist, dann bist Du vermutlich auch ziemlicher 
Anfänger. Das waren wir alle mal - und viele haben solchen Code 
geschrieben wie Du.

Du sagst das es so halbwegs geht: Es wäre aber vermutlich doch nützlich 
und würde Deine Note verbessern, wenn Du uns den kompletten Code hier 
postest und die Kritiken dazu liest und den Code weiter verbesserst.

Ich weiß, Kritik ist nicht nur angenehm und manchmal ist der Ton hier 
sehr rau. Aber es wäre auch nützlich, wenn es Dir gelänge, das möglichst 
zu ignorieren.

Kritisch finde ich, die Verwendung von Interrupts zur Tastenbehandlung 
und vor allem die Verwendung von Verzögerungen in Interrupts. Letzteres 
ist für einen Anfänger unter allen Umständen zu vermeiden. Ersteres kann 
man mit Erfahrung - wenn man es zwangsweise tun MUSS - irgendwie 
hinkriegen. Aber der Profi vermeidet das, wie Senf auf der Kirschtorte.

Eine der Hauptschwierigkeiten für Anfänger besteht darin, sich den 
tatsächlichen Ablauf ihres Programms irgendwie vorzustellen. Das zu 
lernen und zu üben, ist ein Problem vor dem jeder mal steht.
Das kann man mit verschiedenen Methoden angehen, von denen Du die für 
Dich beste erst einmal herausfinden musst.
Ich schlage Dir vor, dass Du Dir einen Zeitstrahl auf einem grossen 
Papier hin zeichnest. Ignoriere im ersten Schritt die Interrupts. 
Schreibe wirkliche Zeiten an den Strahl. Eine sinnvolle Aufteilung hängt 
von der Taktfrequenz ab. Bei 1MHz sind das etwa 1 bis 5us. Du musst 
nicht jeden Befehl hinschreiben, aber doch die für die Funktion 
wesentlichen Befehle. Darunter die Verzögerung.

Dann guck Dir den Interrupt an. Nimm den erst einmal als alleinstehenden 
Code als wenn es den anderen nicht gäbe. Nimm den selben Zeitmaßstab wie 
in der vorherigen Zeichnung. Nimm am besten einen zweiten Bogen Papier 
dazu.

Wenn Du das fertig hast, dann lege das Papier mit dem Interrupt mal an 
die Zeitlinie des Hauptprogramms. Wann kann der Interrupt auftreten? 
Vermutlich immer; stimmt es? Was hat es für Folgen, wenn der Interrupt 
kurz vor oder während der Verzögerungen auftritt? Wann werden 
Variablenänderungen im Interrupt für das Hauptprogramm wirksam?

Zu der Entprellung lies mal hier: 
https://www.mikrocontroller.net/articles/Entprellung

Viel Erfolg.

von Matthias L. (Gast)


Lesenswert?

Sinnvoll wäre, mein Kommentar weiter oben nochmal zu lesen...

von Ich D. (martaniu)


Angehängte Dateien:

Lesenswert?

So sieht mein Code bislang aus.
Die idee des Dimmens ist ganz oben.
Hab jetzt die For-schleife rausgenommen mit den 10 sek. und die Variable 
verändert.
Danke für eure hilfe
martaniu


--

Über dem Texteingabefeld steht folgendes:


Wichtige Regeln - erst lesen, dann posten!


Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

-rufus

: Bearbeitet durch User
von Spaghetti (Gast)


Lesenswert?

Ich D. schrieb:
> So sieht mein Code bislang aus.

Ach du Sch....öner Kot.
Das ist Spaghetti vom Feinsten.

von Ich D. (martaniu)


Lesenswert?

Hab den Fehler gefunden :/
Ich kann aus der for-schleife nicht in die if-schleife springen aus der 
else-if raus. Wenn ihr Ideen habt was ich verändern kann immer her 
damit. Schonmal im voraus danke.
Martaniu

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Ich D. schrieb:
> Ich kann aus der for-schleife nicht in die if-schleife springen ...

  http://www.if-schleife.de

von Jörg E. (jackfritt)


Lesenswert?

Frank M. schrieb:
> Ich D. schrieb:
>> Ich kann aus der for-schleife nicht in die if-schleife springen ...
>
>   http://www.if-schleife.de

?

von The D. (thedaz)


Lesenswert?

Ein paar Anmerkungen :

1. du definierst die variable b einmal global und einmal lokal in der 
ISR. Mit sowas legt man sich schnell aufs Kreuz. Schalte mal ein paar 
compiler warnings scharf und versuche den code sauber zu kriegen.

2. globale Variablen, die von ISRs modifiziert werden, solltest du immer 
volatile deklarieren. Ohne volatile optimiert der Compiler eventuell die 
Zugriffe auf eine vermeintlich nutzlose Variable weg.

von Matthias L. (Gast)


Lesenswert?

immer her damit.

Indem Du Dir meine Antwort (ziemlich weit oben) mal durchliest und es so 
umsetzt..

von The D. (thedaz)


Lesenswert?

Vermutlich auch nicht so gewollt ?

Zeile 569 :   if (a==1);

von Rene K. (xdraconix)


Lesenswert?

Vor allem ist das eigentlich ein Paradebeispiel, welches mit einer 
Switch <> Case Anweisung zu machen ist.

von The D. (thedaz)


Lesenswert?

Ich würde generell jedem Programmierer empfehlen, sich mal die Clean 
Code Konzepte zu Gemüte zu führen (google ist dein Freund). Wer diese 
auch nur ein bisschen befolgt, macht es der Gemeinde hier sehr viel 
einfacher, seinen code zu verstehen und zu beurteilen.

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.