if else wird beides gleichzeitig ausgeführt

Gast #1125052
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??
Gast #1125070
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.
Gast #1125077
>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?
Gast #1125085
>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?
Gast #1125089
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
}
#1125090
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.
Gast #1125096
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).
Gast #1126347
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.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 17 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.