Forum: Mikrocontroller und Digitale Elektronik Arduino hängt


von buchna (LEDxxxL) (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

Ich verwende ein Arduino zur Steuerung eines Displays. Dabei werden an 
das Arduino alle 40ms die aktuellen Werte via Funk geschickt. Insgesammt 
sinds 6 Byte alle 40ms.

Mein Problem manchmal hängt sich das Arduino einfach auf. D.h. von ca. 
100mal hängt es sich einmal auf und dann hilft nur neustart. Allerdings 
wenn es mal 1 minute läuft gibt es keine Probleme dann funktioniert die 
Übertragung auch über Stunden ohne Probleme.
1
int RxBytes[100];
2
int RxBytes_alt[10];
3
unsigned long lastTime = 0;
4
int ii = 0;
5
6
while(Serial1.available() > 0)
7
  { 
8
    if((unsigned long)(millis() - lastTime) > 20)
9
    {
10
      ii = 0;
11
    }   
12
    delayMicroseconds(500);
13
    RxBytes[ii] = (int)Serial1.read();
14
    ii++; 
15
    lastTime = millis();
16
  }

Hier ist der Codeteil den ich am ehesten für Schuldig halte. Obwohl er 
in 99% der Fälle funktioniert.

Die 20ms Überprüfung dient dazu falls mal ein Byte verloren geht, dass 
nicht alles falsch ist. D.h. sind zwischen 2 Bytes mehr als 20ms 
vergangen sehe ich dieses neue Byte als ein erstes von 6 Bytes an. 
Funktioniert auch meistens sehr gut.

Im Anhang nochmal das komplette Programm. Hoffe ihr könnt den Fehler 
lokalisieren. "Leider" tritt er nur so selten auf das macht es so 
schwierig.

von Karl M. (Gast)


Lesenswert?

Welchen Zweck verfolgst Du mit ?
1
delayMicroseconds(500);

von Karl M. (Gast)


Lesenswert?

Hallo,

den Fehlerzustand dieser Funktion
1
Serial1.read();
fängst Du auch nicht ab, warum ?

von Wolfgang (Gast)


Lesenswert?

buchna (LEDxxxL) schrieb:
> Mein Problem manchmal hängt sich das Arduino einfach auf. D.h. von ca.
> 100mal hängt es sich einmal auf und dann hilft nur neustart.

Auch wenn es nicht schön ist, den Kopf vor dem Fehler in den Sand zu 
stecken, könnte man das Problem durch einen Neustart verbergen.

Der Watchdog würde sogar jegliche anderen Fehler, die zu Hängern führen 
können, erfolgreich überdecken.

von Pete K. (pete77)


Lesenswert?

Lernt man heute eigentlich nicht mehr, den geschrieben Code auch zu 
dokumentieren?

Schalte einen Debug-Output an (z.B. RS232) und lass Dir ein paar 
Variablen ausgeben. Dann siehst Du auch was passiert.

von W.G. (Gast)


Lesenswert?

Wolfgang schrieb:
> buchna (LEDxxxL) schrieb:
>> Mein Problem manchmal hängt sich das Arduino einfach auf. D.h. von ca.
>> 100mal hängt es sich einmal auf und dann hilft nur neustart.
>
> Auch wenn es nicht schön ist, den Kopf vor dem Fehler in den Sand zu
> stecken, könnte man das Problem durch einen Neustart verbergen.

Das wäre wohl die ultima ratio wenn man den Fehler garnicht findet.

Aber zuerst einmal: Es ist ganz normal in der Praxis, dass Daten nicht 
(korrekt) übertragen werden oder verloren gehen. Auch dass mal ein 
Device nicht reagiert oder ähnliches. Nicht umsonst gibt es in so gut 
wie jeder Kommunikation Checksummen. Um ein Aufhängen (wie in deinem 
Fall) zu verhindern hat jede vernünftig geschriebene Funktion einen 
Fehlerwert den sie im Fall der Fälle zurück gibt. Ist die Funktion 
blockierend, hat sie  einen Timeout.

Ich würde in deinem Fall zuerst einmal die Fehlersuche damit beginnen zu 
schauen, wo genau der Controller hängen bleibt. Bist du dir überhaupt 
sicher, dass der Controller hängen bleibt? Wenn ja wie erkennst du das? 
Poste bitte deinen gesamten Sourcecode.

Karl M. schrieb:
> den Fehlerzustand dieser FunktionSerial1.read();fängst Du auch nicht ab,
> warum ?

Das musst du natürlich machen! Das ist das offensichtlichste was (in dem 
von dir geposteten Codeteil) blockieren könnte.

Wenn du herausfinden willst wo du "rausfliegst" dann mach eine 
unterschiedliche Ausgabe nach jeder (sinnvollen) Zeile deines Codes 
(serial.printline() oder so heißt das) und schau dir das im Arduino 
Terminal an. Dann siehst du zumindest in welcher Zeile du Probleme 
bekommst. (Anderst kann man Arduino ja nicht debuggen).

von buchna (LEDxxxL) (Gast)


Lesenswert?

Danke schonmal für die vielen Antworten!

Leider habe ich wohl meine Symptome falsch beschrieben! Das Arduino 
hängt nicht im Sinne von es tut nichts mehr. Sondern es zeigt nur noch 
Mist an und das Programm macht mehr oder weniger was es will.

Den Delay brauch ich damit das Empfangen von Daten überhaupt 
funktioniert. Ohne diesen Delay werden die Daten nicht richtig gelesen. 
Habe dieses Problem schon im Internet recherchiert allerdings scheint 
dieser Delay nötig zu sein.

Karl M. schrieb:
> den Fehlerzustand dieser FunktionSerial1.read();fängst Du auch nicht ab,
> warum ?

Weil ich nicht weiß wie? Das ich nicht viel weiß ist auch der Grund 
warum ich hier schreibe.

Ein Neustart ist leider keine Option. Da ich nicht weiß wann das Arduino 
"hängt" könnte ich es nur manuell machen.

Watchdogtimer ist sicher ne gute Idee nur leider habe ich den Fehler 
falsch beschrieben deswegen wird das wohl nicht funktionieren.

Wie bereits beschrieben taucht der Fehler nur sehr sehr selten auf. 
Deswegen ist es fast unmöglich den Fehler mit sozusagen Checkpoints 
einzugrenzen.

von Wolfgang (Gast)


Lesenswert?

buchna (LEDxxxL) schrieb:
> Das Arduino hängt nicht im Sinne von es tut nichts mehr. Sondern es
> zeigt nur noch Mist an und das Programm macht mehr oder weniger was
> es will.

Ein Programm macht erstmal gar nichts und der Arduino, der mit dem 
Programm gefüttert ist, macht genau das, was ihm das Programm 
vorschreibt (solange die HW läuft).

Das Problem ist, dass du von deinem Arduino etwas anderes erwartest, als 
du ihm gesagt hast.

von buchna (LEDxxxL) (Gast)


Lesenswert?

Ok danke für die Hilfe.

Werde weiter im Internet suchen.

von Georg (Gast)


Lesenswert?

buchna (LEDxxxL) schrieb:
> Habe dieses Problem schon im Internet recherchiert allerdings scheint
> dieser Delay nötig zu sein.

Ich habe hier in einem ähnlichen Post schon geschrieben, dass es da 2 
Möglichkeiten gibt, um den Empfang zu synchronisieren:

1. ein grösserer zeitlicher Abstand zwischen Datenblöcken, dann benutzt 
der Empfänger einen Timer, der beim Empfang eines Bytes gestartet wird - 
ist die Zeit zum nächsten Byte > x ms, so ist das das erste Byte eines 
neuen Blocks.

2. Spezielle Bytes, z.B. STX zum Start und ETX am Ende eines Records. 
Natürlich dürfen die in den Daten nicht vorkommen, es ist aber sowieso 
besser ASCII-Daten zu übertragen statt binär.

Du benutzt keines von beiden, einfach mal 20 ms einzustreuen ist keine 
Lösung, denn die funktioniert ja nur, wenn die Übertragung vorher schon 
funktioniert hat. Wenn du nicht weisst, das wievielte Byte als nächstes 
kommt, trifft deine Verzögerung irgenwo mitten in die Daten. Und 
natürlich gehört zu einem brauchbaren Protokoll auch noch eine 
Prüfsumme.

Wie sinnvoll DELAY ist, steht noch auf einem ganz anderen Blatt. Dafür 
haben Controller Timer.

Georg

von Pete K. (pete77)


Lesenswert?

Bemühe Dich mal, Fehlerzustände abzufragen, also:
- Rückgabewerte der Funktionen auszuwerten
- Bei If-Abfragen auch den else-Zweig mit auszuwerten
- Klammern richtig setzen (siehe Zeitberechnungen)

Außerdem:
- globale Variablen gehören vor die Funktionen und nicht mitten rein
- int Level = Helligkeit * 255 / 100; -> Sicher, dass das immer mit int 
dargestellt werden kann?
- Serial1.begin(9600); --> Konstanten deklariert man am Anfang, z.B. 
#define BAUDRATE 9600
- Die Sachen hier:
 int RxBytes[100];
int RxBytes_alt[10];
unsigned long lastTime = 0;
int ii = 0;
gehören in die Funktion als lokale Variablen

Ich empfehle, ein C-Buch zu lesen.

von Wolfgang (Gast)


Lesenswert?

Georg schrieb:
> Wie sinnvoll DELAY ist, steht noch auf einem ganz anderen Blatt. Dafür
> haben Controller Timer.

Sofern der Controller nichts anderes zu tun hat und Stromsparen kein 
Thema is, ist es ziemlich egal, ob der µC in einer Delay-Schleife oder 
in einer Warten-auf-Timer-Schleife kreist.

von Karl M. (Gast)


Lesenswert?

buchna (LEDxxxL) schrieb:
> Karl M. schrieb:
>> den Fehlerzustand dieser FunktionSerial1.read();fängst Du auch nicht ab,
>> warum ?
>
> Weil ich nicht weiß wie? Das ich nicht viel weiß ist auch der Grund
> warum ich hier schreibe.
Hallo,

ich sehe das als Ausrede, in der Arduino Welt gibt es eine Webseite mit 
einer Beschreibung zu Serial1.read();.

https://www.arduino.cc/en/Serial/Read

Diese könnte man mal lesen !

Das Delay gehört dort nicht hin und verdeckt etwas anderes, das 
schreibst Du ja selbst.

Auch ist zu überprüfen wie groß der Baudratenfehler bei 9600 ist!
Wie? steht im Datenblatt deines Atmel AVR µC !

von buchna (LEDxxxL) (Gast)


Lesenswert?

Georg schrieb:
> 1. ein grösserer zeitlicher Abstand zwischen Datenblöcken, dann benutzt
> der Empfänger einen Timer, der beim Empfang eines Bytes gestartet wird -
> ist die Zeit zum nächsten Byte > x ms, so ist das das erste Byte eines
> neuen Blocks.

Ist das nicht genau das was ich tue?

von Bastian W. (jackfrost)


Lesenswert?

Mit so was in der Art kannst du das doch einfach abfangen. Vorrssetzung 
ist das du ein Start und ein Stoppzeichen hast. Serial.available gibt 
dir ja die Anzahl der Bytes an die im Puffer sind.
1
if(Serial.available() == AnzahlBytes)
2
{
3
  for(int i=0; i< AnzahlBytes; i++)
4
  {
5
   RxBuffer[i] = (int)Serial1.read();
6
  }
7
  if((RXBuffer[0] == Startzeichen) && (RXBuffer[AnzahlBytes-1] == Stoppzeichen))
8
  {
9
   //Tu was
10
  }
11
  else
12
  {
13
   // Fehlermeldung Synchronität usw
14
  }
15
16
}
17
else
18
{
19
  if(Serial.available() > AnzahlBytes)
20
  {
21
    // Tu was anderes
22
  }
23
}

Wenn du keine Synchronität mehr hast kannst du ja am Stopp oder am 
Startzeichen erkenenn wie groß der Versatz ist und beim nächsten Empfang 
einfach mehr Zeichen erlauben und dann den vorderen Teil abschneiden.

Gruß JackFrost

von Georg (Gast)


Lesenswert?

buchna (LEDxxxL) schrieb:
> Ist das nicht genau das was ich tue?

Kann man nach dem Fragment nicht sagen - du setzt zwar den Index zurück, 
aber was passiert, wenn du nicht synchron bist? Verwirfst du die bis 
dahin empfangenen Bytes? Was passiert überhaupt nach dem Empfang aller 
Bytes?

Fazit ist, du musst mehr Aufmerksamkeit allen denkbaren Fehlern widmen. 
Z.B. ene State Machine, die bei jedem Fehler, auch etwa Parity, 
Prüfsumme usw., den Zustand auf 0 zurücksetzt und erst wieder losläuft, 
wenn sie definitiv ein neues Startbyte erkannt hat.

Georg

von Georg (Gast)


Lesenswert?

Georg schrieb:
> Kann man nach dem Fragment nicht sagen

Nachtrag: da du Fehlermeldungen von Serial1 nicht auswertest, spricht 
deine Pausenerkennung auch auf (physikalische) Empfangsfehler an, was 
aber nicht richtig ist - nach z.B. einem Parity-Fehler startest du mit 
dem nächsten Byte eine neue Übertragung, das ist in 5 von 6 Fällen 
falsch.

Georg

von Narfie (Gast)


Lesenswert?

Und gleichzeitig stellst du nicht sicher, dass ii über seinen erlaubten 
Bereich hinaus wächst.... Das würde auch den "Unsinn" erklären, den du 
empfängst.

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.