Hallo Zusammen, vorab sei gesagt, dass ich seit ca. 6 Monaten aktiv auch hier mitlese, und dadurch sehr viel gernt und gelöst habe.Danke euch! Diesmal konnte aber auch die SuFu mir nicht weiterhelfen...! Ich habe mir einen in den letzten Monaten einen Aquarium Controller entwickelt. Hierbei kommt folgende Hardware zum Einsatz: - Arduino Mega 2560 > Spannungsversorgung über NT mit 9v 500mAh oder USB - Ethernet Shield W5100 mit SD-Steckplatz - 2 Kanal SainSmart Relais Karte (in 2 geteilt) - DS18S20 1-Wire Temperatur-Sensor - EVG von Phillips(Artikelnummer: PH-91008030), 2x54w T5, Dimmbar, steuerung mit 3 GoldCaps via Relay - LCD 1602 (nicht I2C) - RTC DS1307 via I2C - 4 Taster mit vorwiderständen, an Analog Mein Problem ist, das in unregelmäßigen abständen (meisst nach 1-3h) alles einfriert. Durch drücken auf "reset" gehts dann wieder weiter. - problem besteht auch wenn keine Relais & kein Lan angeschlossen sind, - getestet mit verschieden Spannungsversorgungen (USB, Netzteil, Batterien) -hatte den Speicher im Verdacht, daher alle Strings mit dem "F() syntax" in den Flash verschoben. Alles ohne entgültigen Erfolg.... >>Im Anhang findet Ihr den kompletten Code, als .txt & .ino (ist zu lang zum einfügen). Vielleicht findet Ihr ja den/die Fehler und könnt mi helfen?! Auch über Verbesserungsvorschläge freue ich mich! Vielen Dank & viele Grüße, Max
Nabend, dann nehme die auskommentierten "Serial.print(..." wieder rein, baue noch ein paar dazu und zeichne diese auf. MfG
Das ist ne Menge Holz an Code.... und dann noch die Arduino-Libs. Wie gross ist denn das Hex-File, welches der Compiler (Arduino-IDE) ausspuckt ? Ich meine, die Grösse steht nach dem Compile/Link unten in der Statuszeile. Hintergrund der Frage: ist da evtl. zu wenig RAM für den Stack übrig ?
Ich kann mit *.ino, *.txt nichts anfangen. Welche Programmiersprache ist denn das? Ich programmiere in C und da heißen die Programme *.c, *.h. Peter
> da heißen die Programme *.c, *.h.
du meintest wohl Quelltexte.
Peter Dannegger schrieb: > Ich kann mit *.ino, *.txt nichts anfangen. Welche Programmiersprache ist > denn das? > > Ich programmiere in C und da heißen die Programme *.c, *.h. > > > Peter Dieter Nuhr hat dazu mal etwas passendes gesagt.
us73 schrieb: > Das ist ne Menge Holz an Code.... und dann noch die Arduino-Libs. > Ganz schön viel Holz!!! Hallo Max, ohne mich richtig in deinen ganzen Code rein gelesen zu haben, als Erstes würde ich das in Funktionen unterteilen und wenn du dann die Funktionen in neuen Tabs (der Pfeil unter der Lupe für Serial Monitor) unterteilst, dann kannst du das auch irgendwann wieder lesen. So wie du das beschreibst, scheint es für mich zu einem Speicherüberlauf zu kommen, der mit der Zeit zusammen hängen muss. Vielleicht nimmst du mal die Zeitvarianten für einen Test raus? Auch den DS18S20 (nicht vielleicht DS18B20?) fragst du da sehr merkwürdig ab. Da gibt es bessere Beispiele für Arduino. Ich hab das auch immer ganz schnell mit der "Zeit" Probleme bekommen. Auch mit der Delay Funktion gibt es bei größeren Werten (es scheint als würde Arduino alle Delay Werte aufaddieren und dann nicht mehr mit dem Integer Wert hin kommen) schnell Probleme. Dann wird ganz schnell das Durchlaufen immer länger, bis der dann irgendwann einfriert. Wie gesagt, ich hab mir deinen Code nicht völlig angetan, da ich nicht weiß was du dir alles dabei gedacht hast. Mit Delay hab ich dann mal etwas experimentiert und ihn auf "long" gesetzt, danach liefen einige Sachen wieder. Vielleicht ist das ja ein neuer Gedankenansatz für dich? Gruß Frank
Guten Abend, das sind ja viele Antworten! @Frank - es ist 100% ein DS18S20, - der Tipp mit den Delays klingt logisch, teste ich mal. @us73 - fertiggestellt habe ich den Code auf Arduino 1.0.2 - Binäre Sketchgröße: 23.380 Bytes (von einem Maximum von 258.048 Bytes) @Klaus Dieter - schaltung habe ich nur auf der Platine und im Kopf, aber wie erwähnt, auch ohne angeschlossenen Hardware hängt er sich auf. @Joachim Rath - die Serial.print wieder zu aktivieren macht, so glaube ich, wenig sinn, da ich zwar sehen könnte an welcher Stelle er abstürzt, aber nicht weshalb. Da die TXT version irgendwie fehlerhaft war, HIER ein Link zur Online Version des Codes: http://pastebin.com/nLS6A0yv Zusätzlich als PDF im Anhang. Bitte weiter so, gemeinsam schaffen wir das bestimmt! Danke & gute Nacht, Max
Max Fröhlich schrieb: > Mein Problem ist, das in unregelmäßigen abständen (meisst nach 1-3h) > alles einfriert. Durch drücken auf "reset" gehts dann wieder weiter. > - problem besteht auch wenn keine Relais & kein Lan angeschlossen > sind, > - getestet mit verschieden Spannungsversorgungen (USB, Netzteil, > Batterien) > -hatte den Speicher im Verdacht, daher alle Strings mit dem "F() > syntax" in den Flash verschoben. Speicher habe ich irgendwie auch im Verdacht. Hast Du mal versucht, Dir im laufenden Programm die noch freie Speichergröße anzeigen zu lassen? Und sehe ich das richtig, dass Du diese beiden Deklarationen in Deiner loop hast: byte data[12]; String data; Was sagt denn Dein Compiler dazu? Welche Arduino-Version verwendest Du? Sollte das nicht einen "conflicting declaration" Error im Compiler verursachen, genau in der Zeile, in der "data" als String-Objekt deklariert werden soll, nachdem es weiter oben als Byte-Array deklariert wurde? Anyway, ich persönlich würde die String-Objekte ja komplett aus dem Programm rausschmeissen und nur was mit char-Arrays machen. Den dynamischen String-Objekten mit veränderlicher Länge zur Laufzeit des Programms traue ich nicht über den Weg. Die String-Objekte fragmentieren Dir bei ausgiebigem Gebrauch den RAM-Speicher, so dass irgendwann die Speicherverwaltung für einen langen String kein ausreichend großess Stück RAM-Speicher am Stück mehr allozieren kann, und dann ist der eigentlich zugewiesene String nicht da. Beim Programmieren auf Geräten wie einem PC mit einer dynamischen Speichererweiterung in Form von "Auslagerungsspeicher auf Festplatten" mag das zwar alles keine Rolle spielen, aber auf einem Microcontroller ohne Reserve-RAM als Auslagerungsspeicher auf Festplatte, würde ich die C++ String-Objekte im Programm dringend meiden. Meine Tipps zur Einsparung vom RAM-Speicher und zur Vermeidung der Defragmentierung des RAM-Speichers wären: 1. Auf "String" Objekte im Programm komplett verzichten und nur char-Arrays verwenden! Wenn Du auf Komfort bei einer formatierten Textausgabe von Daten nicht verzichten möchtest, verwende zur Formatierung eines char-Arrays die "sprintf()" Funktion! 2. Wenn möglich auch auf "float" im Programm komplett verzichten und stattdessen Temperaturen in Hundertstel-Celsius ermitteln, formatieren und nur mit Ganzzahl-Arithmetik im Programm rechnen!
Nebenbei: 1.Prüfpunkte eingebaut um zu sehen wo oder wann er immer hängt? 2.Man kann auch Speicher prüfen bevor man ihn benutzt.
Hallo, zuerst Danke für euer Feedback! Hier ein Paar Antworten; @Jürgen S. Das Programm, um zu sehen wieviel speicher noch frei ist, kenne ich & werde es einbauen. "Data" Doppel - Wow, unter Verwendung von Arduino 1.0.2 sowie 1.0.1 mekert mein Compiler nicht. Ist mir auch nicht aufgefallen. Wird angepasst und geprüft! "Char-Arrays" anstelle von Strings - Danke für die detaillierte Erklärung!- werde das mal umsetzen und das Ergebniss posten! "sprintf()" kannte ich nicht, habe es mir eben im Arduino Playground angesehen. @Frank Nach meiner Wissen ist "delay" doch eine Funktion. Und irgendwie verstehe ich doch nicht so ganz, wie der auf Long gesetzt werden kann? @oszi40 Prüfpunkte baue ich ein, um zu sehen wo genau alles abstürzt. Die Lebens-Zeiten werde ich dazu per Stoppuhr aufzeichen. Wie soll ich die Aussage "2.Man kann auch Speicher prüfen bevor man ihn benutzt." verstehen? Ich freue mich auf weitere Vorschläge, und versuche (hoffentlich) morgen die neuen Fakten zum geänderten & angepassten Code posten zu können. Danke & Gute Nacht, Max
Max Fröhlich schrieb: > @Frank > Nach meiner Wissen ist "delay" doch eine Funktion. Und irgendwie > verstehe ich doch nicht so ganz, wie der auf Long gesetzt werden kann? Da hast du wohl recht. grins Nachdem ich ähnliche Probleme hatte und die Zeit immer länger wurde, las ich mal auf der Arduino Seite nach. Ich hatte das dann auf millis geändert. Schlag mich tot, aber du kannst doch die Funktion, bzw. den Wert an eine Variable übergeben und der kannst du ein "long" voran stellen. Wenn ich das jetzt noch so richtig weiß. Trotzdem!!!! Es hängt mit deinen Delays zusammen. Gucke mal hier, was auf der Arduino Seite unter Delay an Anmerkung steht. Da ist genau das Problem beschrieben. Caveat While it is easy to create a blinking LED with the delay() function, and many sketches use short delays for such tasks as switch debouncing, the use of delay() in a sketch has significant drawbacks. No other reading of sensors, mathematical calculations, or pin manipulation can go on during the delay function, so in effect, !!!!!it brings most other activity to a halt.!!!!!! (und am Ende den ganzen Progammablauf) For alternative approaches to controlling timing see the millis() function and the sketch sited below. More knowledgeable programmers usually avoid the use of delay() for timing of events longer than 10's of milliseconds unless the Arduino sketch is very simple. Certain things do go on while the delay() function is controlling the Atmega chip however, because the delay function does not disable interrupts. Serial communication that appears at the RX pin is recorded, PWM (analogWrite) values and pin states are maintained, and interrupts will work as they should.
Max Fröhlich schrieb: > "Data" Doppel - Wow, unter Verwendung von Arduino 1.0.2 sowie 1.0.1 > mekert mein Compiler nicht. Ist mir auch nicht aufgefallen. Wird > angepasst und geprüft! Merkwürdig, mein Arduino 1.0.1 meckert beim Kompilieren sofort, wenn beide data-Deklarationen im selben Gültigkeitsbereich untereinander stehen. > "Char-Arrays" anstelle von Strings - Danke für die detaillierte > Erklärung!- werde das mal umsetzen und das Ergebniss posten! > > "sprintf()" kannte ich nicht, habe es mir eben im Arduino Playground > angesehen. Uiuiui, dann bist Du beim Einstieg in C/C++ aber noch nicht weit gekommen. Ich habe ja früher auch nur Turbo-Pascal und PERL programmiert, aber sprintf war eines der ersten Dinge, was ich an C neu entdeckt habe als ich damit anfing. Die sprintf-Funktion ist zwar vergleichsweise schneckenlahm, aber sie macht die unter C vergleichsweise anachronistische Stringbehandlung dann doch einigermaßen komfortabel bei der formatierten Ausgabe von Daten. Übrigens ist sprintf eine recht "unsichere" Funktion, bei der die Länge des Zielpuffers nicht überprüft wird, was zum Überschreiben von falschen Variablenbereichen führen kann, wenn der Zielpuffer zu klein gewählt wurde. Das char-Array für den aufnehmenden String muss bei Verwendung dieser Funktion auf jeden Fall groß genug sein, sonst schreibt die Funktion über das Pufferende hinaus andere Variablen. Das kann zu schwer erkennbaren Fehlern führen. Am besten gewöhnst Du Dir deshalb wahrscheinlich lieber gleich die "sichere sprintf" Variante an, namens "snprintf", bei der auch die Puffergröße übergeben wird, die die Funktion maximal nutzen darf. Also statt: sprintf(buf, format, var1, var2, var3); Besser sicher gegen versehentliches Überschreiben des Pufferendes: snprintf(buf, bufsize, format, var1, var2, var3); bei einem statisch deklarierten char-Array Puffer also einfach snprintf(buf, sizeof(buf), format, var1, var2, var3); Mal ein kurzer Codeschnipsel dazu
1 | char sBuf[50]; |
2 | int temperaturwert=2540; // Celsius * 100 |
3 | int bstat_licht=1; |
4 | int bstat_luefter=0; |
5 | int bstat_heizstab=1; |
6 | int bstat_sonstwas=1; |
7 | snprintf(sBuf,sizeof(sBuf),"entries=%d,%02d|%d|%d|%d|%d&submit=Submit",temperaturwert/100,abs(temperaturwert)%100,bstat_licht,bstat_luefter,bstat_heizstab,bstat_sonstwas); |
Wenn tatsächlich Dein RAM-Speicher knapp wird, dann würde ich auch nicht massenhaft so romanlange Variablennamen an den Webserver übertragen, an den Du offenbar Daten übertragen möchtest. Im Prinzip kannst Du massig Variablenspeicher sparen, wenn Du die Übertragung von "Wiederholungsromanen" weglässt: Ich selbst übertrage immer einen Haufen Daten in einer einzigen Variablen an einen Webserver, die Daten einfach nur mit einem senkrechten Trennstrich getrennt. Und egal ob PERL oder PHP oder eine andere Serversprache, einen String wie "0|1|23,5|xy|456" an den Trennstrichen wieder in einzelne Variablen zu trennen, ist auf dem Webserver ein Einzeiler! Das würde ich mir überlegen, hier einzusparen und immer dieselbe Anzahl Variablen in derselben Reihenfolge zu übertragen, die der Webserver kennt und am Ort dann wieder voneinander trennt. Jedenfalls kannst Du sprintf/snprintf auch die Formatierung einer Komma-Dezimalzahl aus einem Integer-Wert "Hundertstel Celsius" überlassen. Siehe oben. Formatstring dazu für Vor- und Nachkommastellen: "%d,%02d" Und als die beiden Variablen wird einmal das Ergebnis der Ganzzahldivision durch 100 übergeben (temperaturwert/100), und vom positiven Temperaturwert der Rest der Modulo-Division durch 100 (abs(temperaturwert)%100), wobei die Nachkommastellen zweistellig mit ggf. führender Null formatiert ausgegeben wird. Aber wie gesagt, wenn Du vom Controller einfach Hundertstel-Celsius an den Webserver überträgst, wäre auch das auf dem Webserver nur ein Einzeiler, dort die Dezimalstellen bei der weiteren Verarbeitung zu formatieren, statt es schon auf dem Mikrocontroller zu erledigen. Die ganzen delays von mal 1000 und 2000 sehe ich nicht als Problem an, das das Programm zum Halten bringen kann. Aber sie führen natürlich zu lästigen Effekten: Wenn Du nämlich prüfen möchtest, ob eine Taste wenigstens 50 ms lang gedrückt wird und es läuft gleichzeitig ein "delay(2000)", dann kann selbst ein Tastendruck von 1 bis 2 Sekunden Dauer komplett verlorengehen und nicht erkannt werden, und im ungünstigsten Fall muss man bis zu 2050 ms auf den Taster drücken, damit der Tastendruck erkannt und ausgewertet wird. Aber auf solche Feinheiten bei der Benutzer-Interaktion kommt es Dir momentan wahrscheinlich nicht an, wenn das Programm bisher überhaupt nicht dauerhaft läuft. Na ja, vielleicht findest Du noch was!
Ich würde erstmal Ethernet und SD-Karte rausschmeißen und das Programm ohne diese zum Laufen bringen. Ethernert und SD-Karte sind gerne mal Kandidaten für Probleme. Beide müssen als Interrupt im Hintergrund laufen, da sie sehr viel CPU-Zeit belegen können. Insbesondere SD-Karten brauchen oft richtig lange Gedenkpausen, ehe es weiter geht. Und dann soll ja nicht gleich das ganze Programm stehen bleiben. Ich würde auch das lcd_clear rausschmeißen, das bewirkt sichtbares Flackern und sieht sehr unprofessionell aus. Üblich ist es, einfach den alten Text mit dem neuen zu überschreiben. Bei Windows wird ja auch nicht jedesmal der Bildschirm schwarz, wenn was neues angezeigt wird. Da die Programme nicht *.c heißen, ist das Betrachten im Forum eine Qual (kein Syntax Highlighting). Peter
Was mir noch gerade am Quelltext auffällt: Benutzt Du jetzt die serielle Schnittstelle für Ausgaben? Oder nicht? Einerseits sehe ich, dass die "Serial" Initialisierung auskommentiert ist: //Serial.begin(9600); Andererseits sehe ich, dass trotzdem Befehle zur seriellen Ausgabe im Quelltext Deiner loop drinstehen, die nicht auskommentiert sind, z.B.: Serial.print("ROM ="); Weißt Du genau, was das Arduino "Serial" Objekt dann macht? Wenn die Initialisierung mit Serial.begin() fehlt und Du trotzdem Serial.print() benutzt? Solange Du Dein LCD-Display an RX/TX (Digital 0 und 1) angeschlossen hast: LiquidCrystal lcd(0, 1, 2, 3, 6, 5); darfst Du die serielle Schnittstelle an Digital 0 und 1 (RX/TX) jedenfalls nicht verwenden. Also entweder die serielle Schnittstelle an den digitalen Pins 0 und 1 nutzen, oder das LCD-Display an den digitalen Pins 0 und 1 benutzen. Aber nicht beides gleichzeitig.
Jürgen S. schrieb: > Einerseits sehe ich, dass die "Serial" Initialisierung auskommentiert > ist: > //Serial.begin(9600); > > Andererseits sehe ich, dass trotzdem Befehle zur seriellen Ausgabe im > Quelltext Deiner loop drinstehen, die nicht auskommentiert sind, z.B.: > Serial.print("ROM ="); > > Weißt Du genau, was das Arduino "Serial" Objekt dann macht? Wenn die > Initialisierung mit Serial.begin() fehlt und Du trotzdem Serial.print() > benutzt? Muss das nicht auch für den Temperatursensor zwingend da stehen? Der überträgt die Daten doch auch seriell.
Hallo Zusammen, Ihr könnt euch gar nicht vorstellen, wie viel freuede es macht, so viel Feedback, Lösungsvorschläge und Hilfestellung von euch zu erhalten! @Jürgen S. Ich benutze nur das LCD. Die Serielle Schnittstelle verwende ich nur zur Fehleranalyse und bei bedarf. Habe schon den Adapter für LCD1602>I2C liegen, wollte aber jetzt nicht unnötig rumbasteln, bevor die Basis nicht 100% ok ist. @Peter Dannegger, @Jürgen S., @Frank O. Ich schaffe es zeitlich nicht vor Freitag Abend alles umzusetzen & zu implementieren, melde mich aber dann wie versprochen, mit Resultaten, Feedback & dem neuem Code. Vielen Dank & Grüße, bis Freitag, Max PS: Natürlich sind weitere Infos & Feedback immer willkommen. :-)
Keine Ahnung was bisher so an Input kam, aber beim Debuggen ist es immer gut den Fehler einzugrenzen. Also in der Hauptschleife eine LED blinken lassen und alle Aufrufe zu sonst irgendwas auskommentieren. Nach 4 Stunden fehlerfreiem Lauf dann ein Gerät/Schnittstelle/Port dazuschalten. Und dann wieder von vorne. Wenn Du Glück hast, hängt er sich schon am ersten Tag auf.
Danke!!! Es läuft alles wie nie zuvor! Dank euerer Hilfe habe ich mein Problem lösen können. Der Sketch / der Code läuft seit gestern ohne probleme. Auch die Übertragung zu Google klappt super. Genial! Die Ursache war, wie bereits von "Jürgen S." vermutet; die Lösung "Char-Arrays" anstelle von Strings einzusetzen, als snsprintf Variante. Mit Hilfe von Prüfpunkten, wurde der Fehler schnell lokalisiert, und der Code angepasst. HIER der Link für den funktionierenden Code: http://pastebin.com/eFW7ys4t PS: Ein kleines Problem bleibt jedoch, die RTC läuft irgendwie nicht weiter wenn ich die Spannungsversorgung trenne. Sie merkt sich nur die Uhrzeit, wann ich das letzte mal die Uhr eingestellt habe, und startet dann wieder mit dieser Uhrzeit. Aber dafür finde ich/wir bestimmt auch noch eine Lösung. Noch mal an dieser Stelle, danke für eure unermüdliche Hilfe, eure Tips und Ratschläge, insbesondere Jürgen S. für seine umfangreiche Erklärung! PPS: Wenn Ihr GELEGENTLICH einen original Schaltplan oder ein original Service Dokument, oder original Firmware von einem Handy (Samsung, Nokia, LG, HTC, oder Sony(-Ericsson) benötigt, kann ich sehr vielleicht helfen...! >>>Bitte nur per Direkt-Nachricht an mich.
Max Fröhlich schrieb: > Es läuft alles wie nie zuvor! Freut mich zu hören, dass Du das Problem mit den Programmhängern beseitigen konntest! Max Fröhlich schrieb: > PS: Ein kleines Problem bleibt jedoch, die RTC läuft irgendwie nicht > weiter wenn ich die Spannungsversorgung trenne. Sie merkt sich nur die > Uhrzeit, wann ich das letzte mal die Uhr eingestellt habe, und startet > dann wieder mit dieser Uhrzeit. Sorry, Du verwendest zwar eine RealTimeClock-Library, aber Du verwendest KEINE RealTimeClock:
1 | RTC_Millis RTC; |
2 | ...
|
3 | RTC.begin(DateTime(__DATE__, __TIME__)); |
Du verwendest tatsächlich nur den Millis-Systemtakt des Controllers, über den die fortlaufende Zeitzählung für die "Echtzeit" realisiert wird. Beim Kompilieren Deines Codes wird die Startzeit der Uhr fest auf das Datum und die Zeit eingestellt (_DATE_, _TIME_) an dem das Programm kompiliert wurde. Und bei jedem Reset fängt die Uhr genau mit diesem Datum und dieser Uhrzeit neu an zu laufen. Wenn Du eine Realzeit für Deinen Controller benötigst, dann mußt Du noch eine RTC in Deine Schaltung einbauen und die entsprechenden RTC-Routinen aus Deiner Library verwenden, um alle paar Stunden die "echte Realzeit" aus der RTC auszulesen und die Systemzeit abzugleichen. Oder eine DCF77-Funkuhr einbauen, von der die Zeit kommt, inklusive Sommer-Winterzeitumstellung. Oder ein EthernetShield dranbauen, ans Internet anschließen und die aktuelle Zeit von einem Zeitserver holen. Aber so wie Du es jetzt programmiert hast, fängt die Uhr bei jedem Reset immer genau zu der Zeit an zu laufen, zu der Du das Programm kompiliert hast.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.