If Else geht nicht

#4478223
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
Gast #4478255
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.
#4478267
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.
Gast #4478277
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
}
#4478294
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.
Gast #4478505
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.
#4479618
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
Angehängte Dateien:
#4480279
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.

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