mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Sehr komisches Problem mit while-Schleife


Autor: Jan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also ich habe ein kleines Protokoll zur Datenübertragung mit dem PC 
implementiert, welches beim Empfang eines gültigen (nach CRC Prüfung 
usw) Steuercodes die globale Variable "usart_cmd_recv" auf das 
empfangene Kommando setzt, der Empfang ist Interrupt-gesteuert. Ich 
hatte bisher gar keine Probleme. Im Hauptprogramm wird in einer while(1) 
Schleife unter anderem überprüft ob ein Kommando angekommen ist 
(usart_cmd_recv != 0) und dann wird eine switch-case Abfrage gemacht und 
je nach dem welches Kommando empfangen wurde die ein oder andere 
Funktionen ausgeführt.
Eine Funktion dient dazu Daten vom PC ins EEPROM zu schreiben. Diese 
Funktion wird auch aufgerufen und ein ACK wird zurückgesendet danach 
kommt folgende while schleife:

while(usart_cmd_recv != EEPROM_DATA_START) {
  // Implement TIME OUT
}

Diese Schleife soll einfach nur darauf warten, dass der PC das Kommando 
EEPROM_DATA_START sendet, aber wenn das passiert wird die Schleife 
einfach nicht beendet, woran kann das liegen. Ich kann mit sicherheit 
sagen, dass das programm zugriff auf die Variable hat, weil wenn ich die 
Schleife folgendermaßen konstruiere:

while(usart_cmd_recv != WRITE_EEPROM_DATA) {
  // Implement TIME OUT
}

wird die Schleife nicht ausgeführt, da WRITE_EEPROM_DATA das Kommando 
ist um die Funktion aufzurufen ...

Autor: Severino R. (severino)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hast Du usart_cmd_recv als volatile deklariert?

Autor: Gunb (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hello,

also so richtig verstehen tue ich den genauen Ablauf deines Programms 
nicht, hab' aber auch nur flüchtig gelesen.

Aber vielleicht ziehst du mal folgenden Ansatz in Betracht: Wenn das 
EEPROM mit Schreibvorgängen beschäftigt ist, kann/wird eventuell selbst 
ein per Interrupt empfangenes Zeichen verloren gehen. Der Controller 
verhindert nämlich währenddessen ein korrumpiertes Schreiben ins EEPROM 
durch Ignorieren anderer Events.

Ich hatte das Problem bei mehreren Geräten, die seit Jahren zuverlässig 
über RS232 kommunizierten. Nach Einsatz von USB-Konvertern ging dann am 
Ende der Übertragung immer ein Byte verloren. Die Untersuchung des 
Problems hatte dann ergeben, dass durch leichte Änderung des Timings 
durch den Einsatz des USB-Seriell-Konverters, das verlorene Byte immer 
beim Zugriff auf's EEPROM des Controllers (Atmel M128) ankam.

Da kann man sich eventuell den Wolf suchen, bis man das findet! Schau 
doch mal, ob du einen ähnlichen Konstrukt bei dir vorliegen hast und 
spiel mal mit verzögerten Transfers.


Gruss
Gunb

Autor: Jan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also zu dem Zeitpunkt wird noch gar nichts geschrieben. Die Variable ist 
in der Datei usart.c als
unsigned char usart_cmd_recv = 0;
am Dateianfang außerhalb jeder Funktion deklariert. In der Datei 
eeprom.c wird sie am Anfang mit
extern unsigned char usart_cmd_recv;
eingebunden, genauso wie in der Datei welche die main Funktion enthält 
und dort läuft alles ohne Probleme.

Autor: Jan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die aufgerufene Funktion erwartet auch erst später die zu schreibenden 
Daten weil mit der Funktion der ganze EEPROM beschrieben werden kann. 
Erst kommt das bereits gennante START Kommando was der Funktion 
eigentlich nur sagt das nächste Kommando enthält Daten uns soll ins 
EEPROM geschrieben werden und dann könnten nochmal Daten kommen solange 
bis das Kommando EEPROM_WRITE_END gesendet wird. Die Daten werden in 
32Byte Blöcken gesendet.

Autor: schon wieder ein gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Severino hat den wesentlichen Hinweis gegeben: volatile

Autor: Gunb (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
so,

habe mir die Zeit genommen, noch mal genau zu lesen (sorry, hatte vorher 
ne Baustelle vor der Tür).

Schliesse mich den beiden Vorgängern an. Wäre aber interessant zu 
wissen, ob du Erfolg mit 'volatile' hattest?!

Gruss
Gunb

Autor: Michael G. (linuxgeek) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Immer den ganzen wesentlichen Quelltext posten, nicht nur Fetzen. Sonst 
kann keiner was dazu sagen, nur raten.

Autor: Εrnst B✶ (ernst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Naja, der Fetzen hat schon gereicht... Leere Whileschleife soll auf 
Variable warten. Kann daher nur aus nem Interrupt geändert werden.
=> volatile vergessen.

Autor: Jan (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jo, also mit volatile funktioniert das, besten Dank. Jedoch versteh ich 
den Grund ehrlich gesgat nicht so genau. Hab nochmal mein C Buch 
rausgekramt, (The C Programming Language von Brain W. Kernighan und 
Dennis M. Ritchie) selbst da steht nur sehr wenig zu volatile ...

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>volatile

weist den Compiler an, diese Variable bzw. einen Zugriff darauf nicht 
wegzuoptimieren, wenn er der "Meinung" ist, dass er sie wegoptimieren 
könnte.
Aus seiner Sicht wird sie nicht geändert und ist deswegen "über"...
Dass sie in einer ISR geändert wird (Regelfall für die Verwendung von 
"volatile"), kann er bei der Übersetzung eines anderen Programmteils 
nicht "sehen".

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Entwickler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In der Tat ist es so, dass der Compiler zur Compilierzeit den Inhalt der 
Variable noch nicht kennt. Der Zugriff kann also nicht komplett 
wegoptimiert werden. Letztendlich schaut der erzeugte Assemblercode so 
aus, dass das Programm die Variable einmal (wegen Optimierung) in ein 
Register lädt. Anschließend (in der while-Schleife) wartet das Programm 
nur noch auf eine Änderung des Registerinhalts, der natürlich nie 
eintritt, anstatt immer wieder den tatsächlichen Variablenwert zu lesen. 
Das schafft dann aber der Zusatz volatile.

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.