mikrocontroller.net

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


Autor: Zenk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
also ich hab folgenden Code in dem Interrupt Vektor vom USART eines 
ATMega8:
uint8_t RX_CRC = 0;
uint8_t RX_Frame_len = 0;
uint8_t RX_data_len = 0;
uint8_t RX_Identifier = 0xFF;
uint16_t RX_CRC_SUM = 0;


ISR (USART_RXC_vect) {
  uint8_t Addr;
  uint8_t RX_Byte;

  RX_Byte = UDR;

  if (RX_Byte & 128){
//Startbyte
    Addr = (RX_Byte & 7);
    RX_data_len = ((RX_Byte >> 3) & 0x0F);
    RX_Frame_len = RX_data_len + 1;
    RX_CRC_SUM = (RX_Byte & 127);
    RX_Identifier = 0xFF;
    PORTB ^= (1<<PB0);                      // <---- Toggle LED 1
  }
  else if (RX_Frame_len > 0){
    if (RX_Identifier == 0xFF) RX_Identifier = RX_Byte;
    if (RX_Frame_len == 1){
      RX_CRC = RX_Byte;
      if ((RX_CRC_SUM % 128) == RX_CRC) {
        PORTB ^= (1<<PB1);                  // <---- Toggle LED 2
        pfunc = Botschaftsliste[RX_Identifier];
  //      (*pfunc)();    //Funktion entsprechend des Identifiers aufrufen
      }
      else {    // CRC-Prüfung nicht bestanden
        PORTB ^= (1<<PB2);                 // <---- Toggle LED 3
      //
      }
    }
    else {
      RX_CRC_SUM += RX_Byte;
    }
    RX_Frame_len--;
  }
}


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??

Autor: Skua (Gast)
Datum:

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

Autor: Klugscheisser (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Zenk (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Skua (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In der ISR Puffer füllen Flag setzen und in Mainloop verarbeiten.

Autor: Klugscheisser (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?
while(flag) ...

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

Autor: Klugscheisser (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also, vielleicht auch:
volatile uint8_t flag;
volatile uint8_t RX_Byte;

ISR ISR (USART_RXC_vect) {
  RX_Byte = UDR;   // vielleicht einen Ringbuffer einsetzen?
  flag = 0;
}

main () { .....
   while (1) {
      while(flag); // falls flag 0 wird, sobald Zeichen da ist

      tu_was_unterfunktion ()
   }
}


tu_was_unterfunktion () {
  if (RX_Byte & 128){
//Startbyte
    Addr = (RX_Byte & 7);
    RX_data_len = ((RX_Byte >> 3) & 0x0F);
    RX_Frame_len = RX_data_len + 1;
    RX_CRC_SUM = (RX_Byte & 127);
    RX_Identifier = 0xFF;
    PORTB ^= (1<<PB0);                      // <---- Toggle LED 1
  }
  else if (RX_Frame_len > 0){
    if (RX_Identifier == 0xFF) RX_Identifier = RX_Byte;
    if (RX_Frame_len == 1){
      RX_CRC = RX_Byte;
      if ((RX_CRC_SUM % 128) == RX_CRC) {
        PORTB ^= (1<<PB1);                  // <---- Toggle LED 2
        pfunc = Botschaftsliste[RX_Identifier];
  //      (*pfunc)();    //Funktion entsprechend des Identifiers aufrufen
      }
      else {    // CRC-Prüfung nicht bestanden
        PORTB ^= (1<<PB2);                 // <---- Toggle LED 3
      //
      }
    }
    else {
      RX_CRC_SUM += RX_Byte;
    }
    RX_Frame_len--;
  }
  flag = 1;
}


Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Klugscheisser (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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).

Autor: Zenk (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: KellerKollege (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
LED3 = CRC NOK

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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.