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
intRxBytes[100];
2
intRxBytes_alt[10];
3
unsignedlonglastTime=0;
4
intii=0;
5
6
while(Serial1.available()>0)
7
{
8
if((unsignedlong)(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.
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.
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.
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).
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.
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.
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
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.
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.
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 !
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?
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.
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
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
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
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.