Forum: PC-Programmierung Und wird nicht wahr


von Thorsten (Gast)


Angehängte Dateien:

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

von Andreas B. (bitverdreher)


Lesenswert?

Wie wäre es mit:
if(MessageComplete && (Buffer.ByteCount<>0))

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Wie sieht die Deklaration/Definition von MessageComplete aus?

Ich vermute einen klassischen Fall von vergessenem "volatile". Der 
Compiler hat so gar keine Idee, dass MessageComplete von außerhalb 
seines Sichtbereichs modifiziert werden kann, folglich baut der die 
Abfrage nur einmal am Anfang der Schleife ein.

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


Lesenswert?

Andreas B. schrieb:
> Wie wäre es mit:
> if(MessageComplete && (Buffer.ByteCount<>0))

syntax error

von Sebastian R. (sebastian_r569)


Lesenswert?

Jörg W. schrieb:
> syntax error

!=0 anstelle von <>0

Das ist vermutlich C und kein Pascal ;-)

von Andreas B. (bitverdreher)


Lesenswert?

Jörg W. schrieb:
> syntax error

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

Sebastian R. schrieb:
> Das ist vermutlich C und kein Pascal ;-)

Gut geraten :-) Bin meist in Pascal unterwegs

: Bearbeitet durch User
von Thorsten (Gast)


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.

von Thorsten (Gast)


Lesenswert?

volatile uint8_t MessageComplete = 0;  ist auch drin.

von Nop (Gast)


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.

von Nop (Gast)


Lesenswert?

Thorsten schrieb:
> volatile uint8_t MessageComplete = 0;  ist auch drin.

Reicht nicht. Buffer.Count muß auch volatile sein. Eher sogar das 
komplette Buffer-Struct, weil sonst der Rest schiefgeht.

von Thorsten (Gast)


Lesenswert?

Jupp danke, das war der Fehler. Vergessen den Byte.Count volatile zu 
deklarieren. Wäre aber schick zu wissen, warum die while Abfrage 
trotzdem funktioniert hat? Zufall oder C Voodoo?

von MaWin (Gast)


Lesenswert?

Andreas B. schrieb:
> Wie wäre es mit:
> if(MessageComplete && (Buffer.ByteCount<>0))

Steht da doch.
Allerdings wird MessageComplete schnell wieder auf 0 gesetzt.

von Programmieroldie (Gast)


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.

von Thorsten (Gast)


Lesenswert?

Hallo Oldie,

auch ein paar sehr gute Hinweise, Danke. Die Idee mit den Pointern 
gefällt mir. Macht die Struktur ja auch noch etwas schlanker.

Gruß Thorsten

von Wilhelm M. (wimalopaan)


Lesenswert?

Thorsten schrieb:
> Man wie verpeilt bin ich heute eigentlich. Bedanke mich schon im Namen
> von meinem Arbeitskollgen. Der Kugelt sich auch schon auf dem Boden.

Ist das wirklich der erste Ringbuffer, den ihr in Eurer Firma 
realisiert?

von Wilhelm M. (wimalopaan)


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.

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.