Forum: Compiler & IDEs if else wird beides gleichzeitig ausgeführt


von Zenk (Gast)


Lesenswert?

Hallo,
also ich hab folgenden Code in dem Interrupt Vektor vom USART eines 
ATMega8:
1
uint8_t RX_CRC = 0;
2
uint8_t RX_Frame_len = 0;
3
uint8_t RX_data_len = 0;
4
uint8_t RX_Identifier = 0xFF;
5
uint16_t RX_CRC_SUM = 0;
6
7
8
ISR (USART_RXC_vect) {
9
  uint8_t Addr;
10
  uint8_t RX_Byte;
11
12
  RX_Byte = UDR;
13
14
  if (RX_Byte & 128){
15
//Startbyte
16
    Addr = (RX_Byte & 7);
17
    RX_data_len = ((RX_Byte >> 3) & 0x0F);
18
    RX_Frame_len = RX_data_len + 1;
19
    RX_CRC_SUM = (RX_Byte & 127);
20
    RX_Identifier = 0xFF;
21
    PORTB ^= (1<<PB0);                      // <---- Toggle LED 1
22
  }
23
  else if (RX_Frame_len > 0){
24
    if (RX_Identifier == 0xFF) RX_Identifier = RX_Byte;
25
    if (RX_Frame_len == 1){
26
      RX_CRC = RX_Byte;
27
      if ((RX_CRC_SUM % 128) == RX_CRC) {
28
        PORTB ^= (1<<PB1);                  // <---- Toggle LED 2
29
        pfunc = Botschaftsliste[RX_Identifier];
30
  //      (*pfunc)();    //Funktion entsprechend des Identifiers aufrufen
31
      }
32
      else {    // CRC-Prüfung nicht bestanden
33
        PORTB ^= (1<<PB2);                 // <---- Toggle LED 3
34
      //
35
      }
36
    }
37
    else {
38
      RX_CRC_SUM += RX_Byte;
39
    }
40
    RX_Frame_len--;
41
  }
42
}


Nun ist es so dass LED 1 und LED 3 öfters gleichzeit getoggelt werden, 
obwohl dieser Fall von der if - else Logik doch niemals auftreten 
dürfte.

Wie kann das sein??

von Skua (Gast)


Lesenswert?

>Nun ist es so dass LED 1 und LED 3 öfters gleichzeit getoggelt werden,
Sicher?
Ich tippe mal auf schnell hintereinander.

von Klugscheisser (Gast)


Lesenswert?

Also, die Verarbeitung aus der ISR herauszulösen und in der 
Hauptschleife erledigen (bzw. in einer Unterfunktion).
ISR sollten grundsätzlich so kurz wie möglich sein. (Und dann nochmal um 
die Hälfte gekürzt :-) ).

Dann würde ich weiterschauen.

von Zenk (Gast)


Lesenswert?

>Ich tippe mal auf schnell hintereinander.
Ich sende nur alle 500ms ein Byte. Von daher sieht man das deutlich sehn 
ob es gleichzeitig statt findet oder nicht, zumindest wenn der 
Interrupt-Aufruf so funktioniert wie er soll.

>Also, die Verarbeitung aus der ISR herauszulösen und in der
>Hauptschleife erledigen (bzw. in einer Unterfunktion).
Aber was bringt das denn? Wenn ich eine Unterfunktion aus der ISR 
Aufrufe muss die Unterfunktion ja auch erst abgearbeitet werden bevor 
die ISR dann zu Ende bearbeitet wird (und sei es nur die Klammer (}) zu 
schliessen. Das einzige was etwas bringen würde imho wäre aus der ISR 
ein Flag zu setzen und das mit einem Timer abzufragen. Oder liege ich da 
komplett falsch?

von Skua (Gast)


Lesenswert?

In der ISR Puffer füllen Flag setzen und in Mainloop verarbeiten.

von Klugscheisser (Gast)


Lesenswert?

>Aber was bringt das denn?

Das die ISR nicht so lange dauert.

Ich schrieb:
>>Also, die Verarbeitung aus der ISR herauszulösen und in der
>>Hauptschleife erledigen (bzw. in einer Unterfunktion).
und meinte das die Verarbeitung textuell in der Hauptschleife stehen 
soll, oder aus der Hauptschleife eine Unterfunktion aufgerufen wird, 
welche die Verarbeitung erledigt.

Ich meinte nicht_ das Du die Verarbeitungs nur _textuell aus der ISR 
herausnehmen und in eine Unterfunktion setzen sollst, nur um diese 
Unterfunktion dann entweder aus der ISR oder der Hauptschleife aus 
aufzurufen.

Der Satz hätte vielleicht besser lauten sollen:
...in der Hauptschleife erledigen (bzw. in einer Unterfunktion die dann 
aus der Hauptschleife aufgerufen wird).

>und das mit einem Timer abzufragen
Einfach ohne timer, nur das Flag abfragen. Wozu ein Timer?
1
while(flag) ...

Das mit der gleichzeitigkeit kann eigentlich nicht sein, wenn der 
Quelltext so stimmt. Kannst Du das mal mit nem Oszi prüfen?

von Klugscheisser (Gast)


Lesenswert?

Also, vielleicht auch:
1
volatile uint8_t flag;
2
volatile uint8_t RX_Byte;
3
4
ISR ISR (USART_RXC_vect) {
5
  RX_Byte = UDR;   // vielleicht einen Ringbuffer einsetzen?
6
  flag = 0;
7
}
8
9
main () { .....
10
   while (1) {
11
      while(flag); // falls flag 0 wird, sobald Zeichen da ist
12
13
      tu_was_unterfunktion ()
14
   }
15
}
16
17
18
tu_was_unterfunktion () {
19
  if (RX_Byte & 128){
20
//Startbyte
21
    Addr = (RX_Byte & 7);
22
    RX_data_len = ((RX_Byte >> 3) & 0x0F);
23
    RX_Frame_len = RX_data_len + 1;
24
    RX_CRC_SUM = (RX_Byte & 127);
25
    RX_Identifier = 0xFF;
26
    PORTB ^= (1<<PB0);                      // <---- Toggle LED 1
27
  }
28
  else if (RX_Frame_len > 0){
29
    if (RX_Identifier == 0xFF) RX_Identifier = RX_Byte;
30
    if (RX_Frame_len == 1){
31
      RX_CRC = RX_Byte;
32
      if ((RX_CRC_SUM % 128) == RX_CRC) {
33
        PORTB ^= (1<<PB1);                  // <---- Toggle LED 2
34
        pfunc = Botschaftsliste[RX_Identifier];
35
  //      (*pfunc)();    //Funktion entsprechend des Identifiers aufrufen
36
      }
37
      else {    // CRC-Prüfung nicht bestanden
38
        PORTB ^= (1<<PB2);                 // <---- Toggle LED 3
39
      //
40
      }
41
    }
42
    else {
43
      RX_CRC_SUM += RX_Byte;
44
    }
45
    RX_Frame_len--;
46
  }
47
  flag = 1;
48
}

von Stefan E. (sternst)


Lesenswert?

Zenk wrote:

> Ich sende nur alle 500ms ein Byte.

Wie bzw. womit? Sicher, dass immer nur ein Byte gesendet wird?

Wenn ja, würde ich mal den restlichen Code nach "PORTB" durchforsten, ob 
da nicht versehentlich irgendwo auch die entsprechenden Bits 
angesprochen werden.

von Klugscheisser (Gast)


Lesenswert?

Je nach Betriebssystem und sonstigen Umständen, könnte es schon sein, 
das zwei Bytes, von denen DU meinst sie würden mit 500ms Abstand 
geschickt mit wesentlich geringerem (oder auch grösserem Abstand) 
gesendet werden. Deswegen lohnt sich einerseits die Abtrennung der 
Verarbeitung (weil Du die dann einzeln, z.B. auch auf dem Host testen 
kannst) und das konrollieren der LEDs oder der UART-Leitungen mit dem 
Oszi (weil Du die tatsächlichen Abstände siehst).

von Zenk (Gast)


Lesenswert?

der LogicAnalyzer hat gezeigt dass sich 1,15 ms zwischen dem Schalten 
der beiden PORT-Pins befinden. Also definitiv nicht der gleiche Zyklus.

>> Ich sende nur alle 500ms ein Byte.
>Wie bzw. womit? Sicher, dass immer nur ein Byte gesendet wird?

Der Sender ist ebenfalls ein ATMega8. Ich werde den Code mal den 
Empfehlungen nach Umschreiben, mal schauen was dabei raus kommt.
Ein Betriebssystem ist übrigens nicht drauf und da ich auch beim Sender 
bei jedem gesendeten Byte eine LED toggle hab ich auch hier eine ganz 
gute Kontrolle.


Danke schonmal für die Hilfe.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

> 1,15 ms zwischen dem Schalten der beiden PORT-Pins befinden.
Da passt bei 9600 genau ein Byte (mit Start, 8 Daten, Parity, Stop) rein 
;-)

Wird da evtl. gleich noch ein zweites Byte hinterhergeschickt?

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


Lesenswert?

Es gibt auch keinerlei Fehlerauswertung.  Es könnte also durchaus
auch ein Byte gesendet werden, aber auf Grund einer Störung (oder
falscher Baudrate?) als zwei Bytes erkannt werden.

von KellerKollege (Gast)


Lesenswert?

LED3 = CRC NOK

Da stimmt etwas, wie Jörg schon schrieb, nicht mit deiner UART.

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.