Und wird nicht wahr

Gast #6061373
Lesenswert?

Guten Morgen,

es ist mal wieder Brett-vorm-Kopf Zeit.  Ich gucke jetzt eine halbe 
Stunden auf meinen Quellcode und verstehe gerade die Welt nicht mehr. 
Der Fehler muss dermaßen dämlich sein, dass ich nicht drauf komme, was 
ich falsch mache. Vielleicht hat ja jemand von euch gerade den richtigen 
Druchblick, aber der Reihe nach. Ich habe einen Ringbuffer, in den ich 
Daten schreibe. Dazu einen ByteCount wie voll der Buffer ist. Daten 
werden per UART in den Buffer geschrieben und wenn ich CR/LF Empfangen 
habe, soll die Nachricht verarbeitet werden. Oder momentan zum Debuggen 
nur wieder ausgegeben. Klappt auch alles, bis auf ein paar Sonderfälle, 
die Systembedingt sind. Für die muss ich jetzt passende Workarrounds 
bauen. Einer dieser Workarrounds ist die Abfrage, dass nicht nur die 
Nachricht korrekt Empfangen wurde, was ja durch CR/LF erreicht wird, 
sonder dass auch wirklich Daten im Puffer sind. Könnte ja jemand nur 
CR/LF senden.
1
while (1)
2
  {   
3
        if(MessageComplete && Buffer.ByteCount)          //Received CR or RX Buffer is full and there is data in the buffer without triggering the watch dog timer
4
        {
5
      switch (RingBuffer_Read(&Buffer))          //Use first byte of RingBuffer to identify commando message 
6
      {
7
      case 'A':                      //65 = Ascii A
8
         while(Buffer.ByteCount)            //As long as the message was 
9
        {  
10
          while(!(USARTC0.STATUS & USART_DREIF_bm));  //Check that transmission buffer is empty
11
          USARTC0.DATA = RingBuffer_Read(&Buffer);  //Send out single byte of message
12
        }
13
        break;
14
      case 'M':                      //77 = Ascii M
15
        BSMeasResult = PerformMeasurement();      //Do a single Basestation measurement
16
        while(!(USARTC0.STATUS & USART_DREIF_bm));      //Check that UART Tx is ready
17
            USARTC0.DATA = BSMeasResult;          //Transmit Basestation measurement result to Matlab
18
        break;
19
      default:
20
        /* code */
21
        break;
22
      }
23

24
    MessageComplete = 0;                  //Command message was completely processed
25
        }
26
    }

Also Prüfung auf MessageComplete && Buffer.ByteCount. Im Debugger sehe 
ich, dass beide Werte ungleich 0 sind. Was meine Erwartungshaltung ist, 
nur wird die Abfrage nie wahr. Das Programm steht an der Stelle. Nehme 
ich die Abfrage auf ByteCount raus, klappt die If-Abfrage auf 
MessageComplete. Die nachfolgende While Schleife wird auch brav 
abgearbeitet. Buffer_Read zählt den ByteCount runter, die Ausgabe passt. 
Wie kann es also sein, dass das alles Funktioniert, die vermalledeite 
if-Abfrage aber nie Erfüllt wird?

Gruß und Danke,
Thomas
Angehängte Dateien:
Gast #6061388
Lesenswert?

Man wie verpeilt bin ich heute eigentlich. Bedanke mich schon im Namen 
von meinem Arbeitskollgen. Der Kugelt sich auch schon auf dem Boden. Ist 
ja fast so schön wie meine letzte E-Mail Anrede mit Dead Ladies und 
Gentleman...

Aber zurück zum Thema.

if(MessageComplete && (Buffer.ByteCount!=0))
oder if((MessageComplete == 1) && (Buffer.ByteCount !=0 ))

geht auch alles nicht. Schon probiert.
Spannend ist auch folgendes. If(Buffer.ByteCount) wird auch nicht wahr, 
egal ob 1, 2, 3 oder x. Warum aber scheint while(Buffer.ByteCount) zu 
gehen? Das wird sauber durchlaufen bis ByteCount auf 0 steht, egal wie 
groß der Count war.

Gruß der Thorsten und sein vor lachen inzwischen gestorbener und auch 
wenig nützlicher Arbeitskollege Thomas.
Gast #6061392
Lesenswert?

Andreas B. schrieb:

> OK, dann so:
> if(MessageComplete && (Buffer.ByteCount!=0))

Was in C genau dasselbe ist wie

> if(MessageComplete && Buffer.ByteCount)

Jörgs Hinweis mit dem fehlenden volatile sieht mir wesentlich 
zielführender aus. ALLE Variablen, die zwischen Interrupt und 
Applikation geteilt werden, UND wo mindestens einer von beiden 
schreibend zugreift, müssen zwingend volatile deklariert werden.
Gast #6061426
Lesenswert?

Hallo Thorsten,
Bei Ringbuffern mit Bytecount kommt mir immer ein Magengrummeln auf. Das 
Befüllen via UART erfolgt doch in einer IRQ-Routine?
Damit musst du dann das auslesen mit IRQ-Sperre machen da sonst der 
Bytecount mit absoluter Sicherheit irgendwann inkonsistent wird. Ich 
habe mir hier angewöhnt solche Sperren, da gerne Fehlerquelle, wo immer 
möglich zu vermeiden. Es geht tatsächlich ohne: Schreibzeiger der nur 
vom IRQ beschrieben wird, Lesezeiger der nur vom Leser beschrieben wird. 
Schreibzeiger darf Lesezeiger nicht 'überholen' (Buffer voll). 
Lesezeiger = Schreibzeiger bedeutet Buffer leer. Wenn Lese <> Schreib 
kannst du ein Zeichen abholen und zum Interpreter geben. Füllstand ist 
nicht wichtig! nur leer/nicht leer.

Das volatile ist hier natürlich auch nötig, aber du brauchst dich nicht 
zusätzlich um IRQ-Sperrung kümmern als potentielle Fehlerursache.

Da du mit einer while(1) Schleife arbeitest, kannst du die Prüfung auf 
MessageComplete auch in die Case-Zweige nach Empfang Kommandobyte 
verlegen.
Wird in diesem Zustand dann ein CR oder LF statt den Argumenten 
empfangen ist ein Fehler passiert, aktuelles Kommando abbrechen und in 
Hauptschleife zurückspringen. Ansonsten wartet man nach Empfang 'A' dann 
halt in der inneren Warteschleife statt in der oberen. Ist geradeaus 
programmierte Statemachine, wie man sie in Informatik lernen würde.
Du kannst aber auch einen zweiten festen Buffer spendieren in den 
erstmal aus dem Ringbuffer heraus das komplettes Kommando (Ende mit CR) 
zeichenweise kopiert wird, sobald komplett dann an die 
Interpreterfunktion weitergeben. Wäre eine sinnvolle Trennung,braucht 
aber noch paar Byte RAM.
#6061474
Lesenswert?

Programmieroldie schrieb:
> Es geht tatsächlich ohne: Schreibzeiger der nur
> vom IRQ beschrieben wird, Lesezeiger der nur vom Leser beschrieben wird.
> Schreibzeiger darf Lesezeiger nicht 'überholen' (Buffer voll).

Statt "echte" Zeiger kann man auch einen in und einen out Index in 
das Array nehmen. Es gilt dieselbe Überlegung bzgl. konkurrierendem 
Zugriff. Hat kleine Vorteile, wenn man mit Pufferlängen < 256-Bytes 
arbeitet.

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