Hallo Leute,
ich habe mir einen Sketch gebastelt der soweit eigentlich ut
funktioniert, nur habe ich leider ein kleines Problem dabei. Ich kann
entweder den Beschleunigungssensor auslesen oder auf meine SD Karte
schreiben, aber beides gleichzeitig will nicht funktionieren.
Ich benutze die Standard SD-Library von Arduino und eine Library von
Adafruit für meinen ADXL345 Beschleunigungssensor. Das SD-Modul ist über
SPI angebunden und der ADXL345 über I2C was mich noch mehr verzweifelt,
da Sie sich ja da eigentlich garnicht in die Quere kommen dürften.
Ich hoffe jemand hat einen Tip für mich und kann mir helfen das Problem
zu Lösen.
Es soll ein Datenlogger werden, der Die
Uhrzeit/Datum/IR-Signal/Beschleunigungswerte einmal pro sekunde
abspeichert. Gehört eigentlich zu meinem Positionsbestimmungs Thread
aber ich dachte aufgrund des Problems bietet sich ein seperater Beitrag
an. Hoffe das geht in Ordnung.
1
#include<SD.h> // SD
2
#include<Time.h> // Millis
3
#include<Wire.h> // I2C / TWI
4
#include<DS1307RTC.h> // a basic DS1307 library that returns time as a time_t
Der Teil des Beschleunigungssensors ist derzeit auskommentiert. In dem
Fall wird der Datenstring auf SD-Karte gespeichert, so wie es sein soll.
Wenn ich allerdings das kommentieren aufhebe, gibt er mir immer die
Meldung "error openingt test.txt" aus. Er kann also die Datei garnicht
erst öffnen um in sie hinein zu schreiben.
Bin echt für jegliche Hilfe dankbar!
Gruß Vwirt
Vwirt schrieb:> Das SD-Modul ist über SPI angebunden und der ADXL345 über> I2C was mich noch mehr verzweifelt,> da Sie sich ja da eigentlich garnicht in die Quere kommen dürften.
Welches "SD-Modul" verwendest Du?
Pegelwandlung auf 3.3 Volt?
Instabile Stromversorgung des Kartenmoduls?
Hab so ein typisches Breakoutboard von Ebay. Eine 3,3V Pegelwandlung ist
da schon mit drauf. Hätte die möglichkeit das sd modul seperat mit strom
zu versorgen, sollte ich das mal versuchen, könnte das tatsächlich eine
Fehlerquelle sein?
Vwirt schrieb:> Hab so ein typisches Breakoutboard von Ebay.
Welches? Link?
Bei eBay werden ganz unterschiedliche Artikel gehandelt. Und
SD-Kartenmodule, die einen 5V-Spannungswandler drauf haben, müssen
deshalb noch lange keinen 5V-Pegelwandler dabei haben.
Beispiel:
eBay 121277779755 ==> Spannungswandler JA, Pegelwandler NEIN
Andere Module haben Pegelwandler mit drauf, dann meistens aber für
Micro-SD Karten statt für SD-Karten in Standardgröße.
Wenn ein Spannungswandler 5V->3.3V auf der Platine ist, reicht der
Spannungswandler aus, wenn Du das SD-Kartenmodul mit 5V vom
Arduino-Board aus versorgst.
Was allerdings in den meisten Fällen nicht ausreicht: Ein Modul ohne
Pegelwandler direkt an die Arduino 5V-Datenleitungen dranzuhängen.
Habe mal von einem Arduino Uno die 5V angezapft, an dem nichts anderes
dranhängt und damit die Stromversorgung für das SD-Modul gestellt. Damit
funktioniert es komischer weise gleichmal garnicht.
Du könntest mal den Versuch starten den Code ohne folgende Zeilen laufen
zu lassen :
Vwirt schrieb:> int x = ax;> int y = ay ;> int z = az ;>> dataString += " ; x:";> dataString += x;> dataString += " ; y:";> dataString += y;> dataString += "; z:";> dataString += z;> dataString += "; Status:"; */
Die Werte in einen neuen 16 Bit Integer zu kopieren sieht für einen
nicht Arduino Nutzer sinnlos aus, ebenso die Zuweisung eines Integers an
einen String.
Kann es sein das die maximale String Länge erreicht wurde ?
Danke Max,
zur zeit sind die Zeilen ja auch als Kommentar belassen, läuft also ohne
diese Zeilen. Aber ich brauche ja die Beschleunigungsdaten. :(
Woran erkenne ich denn ob die maximale Stringlänge erreicht wurde?
Fehlermeldungen beim kompilieren gibts nicht. :(
Würde sich ja überprüfen lassen indem ich die Beschleunigungswerte in
einen neuen String schreibe und diesen dann mit auf SD Karte schreiben
lasse, oder?
Achso und mit der zuweisung zum integer wollte ich erreichen das aus der
float die mir der Sensor liefert eine Ganzzahl wird.
Int ist doch eigentlich bloß 2byte groß oder irre ich mich da?
Die Idee die dahinter steckt war zu prüfen ob der Beschleunigungssensor
grundsätzlich zusammen mit der SD-Karte (und der RealTimeClock ? )
arbeitet.
Wenn das der Fall ist könnte man einen Hardwarefehler ausschließen.
Sollte heißen diese Zeilen :
Vwirt schrieb:> accel.getAcceleration(&ax, &ay, &az);>> // display tab-separated accel x/y/z values> Serial.print("accel:\t");> Serial.print(ax); Serial.print("\t");> Serial.print(ay); Serial.print("\t");> Serial.println(az);
wider zu aktivieren und zu prüfen ob alles läuft.
Achso, sorry da hab ich dich wohl missverstanden. Werd ich gleich morgen
vormittag mal testen, komme heute leider nicht mehr dazu.
(Ja ne RTC wird auch über I2C mit einbezogen)
Vwirt schrieb:> Habe mal von einem Arduino Uno die 5V angezapft, an dem nichts anderes> dranhängt und damit die Stromversorgung für das SD-Modul gestellt. Damit> funktioniert es komischer weise gleichmal garnicht.
Minimalbeschaltung als Notbehelfs-Levelshifter für Dein Modul an einem
5V Arduino-UNO wäre so etwas, die drei Leitungen CS, MOSI, und SCK am
Mittelabgriff einer Widerstands-Spannungsteilerschaltung abgegriffen:
Nur die MISO-Leitung wird direkt mit Pin-12 verbunden.
Aufgemalt, ungetestet:
Also der Vorschlag von Max hat leider keine Änderung bewirkt, wenn ich
die vorgeschlagenen Code-Zeilen wieder mit rein nehme, kann er wieder
nicht auf die SD Karte zugreifen/schreiben. Bin grad noch am suchen nach
dem Level Converter
Habs intereeshalber auch mal andersrum probiert und nur den Int x, y und
z einfach werte vorgegeben, ohne das der ADXL ausgelesen wird. Dabei
tritt das gleiche Problem auf!
Daher dachte ich, naja vielleicht ist der String ja zu lang, hab also
diese Werte in einen neuen String "dataSring2" gesammelt. Und trotzdem
wieder kein zugriff auf die SD-Karte. Und das obwohl der zweite String
nichtmal mit auf die Karte geschrieben werden sollte. :(
Kann das irgendwie überhaupt nicht nachvollziehen wo es gerade klemmt.
:(
(Levelconverter habe ich leider bislang nicht gefunden und da müssten
auch noch die Stiftleisten angelötet werden, weil ich ihn bislang noch
nicht benutzt habe. Deshalb wird es wohl nix vor heute abend es mit ihm
auszuprobieren)
So gleich mal noch ein kleines Update hinterher. Ich habe mal alles ausm
Code geworfen was nicht zur SD-Karte oder dem Beschleunigungssensor
gehört.
(Außer die includes für die Libraries)
Da funktionieren beide zusammen. Dann hab ich die RTC wieder mit
reingenommen und schon ging es wieder nicht mehr. Andererseits haben ja
vorher die RTC und der BEschleunigungssensor zusammen funktioniert, nur
eben dann die SD-Karte nicht mehr. :(
Sorry das es hier jetzt so häppchenweise kommt. Ich hab mal die RTC mit
dringelassen und lass mir nur die Minute und Stunde per Serial.print
ausgeben, aber ohne es auch noch in den Datenstring schreiben zu lassen.
Da schreibt er fein auf die SD Karte (und liest den Sensor aus!)
Kann es vielleicht wirklich an der Strinlänge liegen oder am SRAM?
Soweit reichen meine Kenntnisse leider nicht um das irgendwie zu prüfen.
:(
JUHU! Es läuft! Hab diesen dummen dataString weggelassen und schreibe
die werte einzeln auf die SD und das klappt 1A. Hab außerdem die
Umwandlung der float werte in Int nochmal geändert ich glaube so sollte
man das eignetlich machen oder?
Falls es jemanden interessiert oder selber mal Teile des Codes braucht
poste ich ihn hier nochmal:
Danke an Jürgen und Max!
1
#include<SD.h> // SD
2
#include<Time.h> // Millis
3
#include<Wire.h> // I2C / TWI
4
#include<DS1307RTC.h> // a basic DS1307 library that returns time as a time_t
Denke nicht das es eine gute Lösung ist.
http://de.wikipedia.org/wiki/SD-Karte#Maximale_Anzahl_der_Schreibvorg.C3.A4nge
Eine SD- Karte kann nicht beliebig oft beschrieben werden, in diesem
Fall wären es 21 Schreibzugriffe pro Sekunde. Vorausgesetzt die Arduino
SD Bibiliothek schreibt bei jedem myFile.print() physikalisch auf den
Speicher und nicht erst beim aufrufen von myFile.close().
Das sollte vorher geklärt werden, bestimmt gibt es in einem Arduino
Forum Hilfe dazu.
Es macht also durchaus Sinn einen großen String einmal auf die Karte zu
schreiben.
Da der Verursacher des Problems anscheinend der dataString ist, wäre
dieser kleine Test möglich :
Vwirt schrieb:> Mit den Schreibzyklen haste natürlich recht, aber zu einem kompletten> String lies es sich ja leider nicht zusammenfassen. :(
Nein, nicht jede print-Anweisung bei offener Datei führt zu einem
Schreibvorgang. Schreibvorgänge werden immer in einem 512-Byte großen
Sektorpuffer zwischengepuffert und tatsächliche Schreibvorgänge auf der
SD-Karte treten auf:
- wenn Du über die 512 Byte Puffergrenze schreibst
- wenn Du die Datei nach dem Schreiben schließt
Das kritische in Sachen "SD-Karte kaputtschreiben" ist dabei nicht das
ständige dranhängen von Daten an eine Datei, so dass diese beim
Schreiben größer und größer wird. Das ist harmlos, weil dabei ja stets
jeder Sektor nur einmal mit Daten beschrieben wird. Erst wenn die Datei
gelöscht wurde, würde dann beim Schreiben einer neuen Datei der Bereich
neu beschrieben werden.
Das kritische ist die FAT (File Allocation Table), bei der nach jedem
Schließen der Datei die dann neue Dateigröße reingeschrieben wird. Der
FAT-Eintrag der Datei bleibt stets an derselben Stelle und wenn Du nach
dem Schreiben die Datei schließt, wird jedesmal an Ort und Stelle die
aktuelle Dateigröße reingeschrieben. D.h. bei jedem "myFile.close();"
wird an derselben Stelle der SD-Karte in die FAT geschrieben.
Machst Du das 86400 mal pro Tag, dann ist der FAT-Sektor nach wenigen
Tagen kaputtgeschrieben und der Kartencontroller muss "Ersatzsektoren"
auf der Karte aktivieren. Das macht er von ganz alleine im Hintergrund.
Allerdings ist die Anzahl der "Ersatzsektoren" auf einer SD-Karte
begrenzt, so dass Du nur eine begrenzte Anzahl Sektoren kaputtschreiben
darfst, ohne dass die Karte komplett unbrauchbar wird.
Mögliche Abhilfe: Weniger häufig auf dieselben Sektoren schreiben. Bei
einem Datenlogger zum Beispiel weniger oft "myFile.close();" verwenden.
Beispiel: Wenn Du bei einem 1-Sekunden-Logging die Datei nur einmal pro
Minute öffnen und einmal pro Minute schließen würdest, könnte der Logger
sechzig mal so lange laufen, bis der FAT-Sektor kaputtgeschrieben ist
und intern gegen einen Ersatzsektor ausgetauscht werden muss.
Nachteil dabei ist allerdings: Wenn Du den Datenlogger abschaltest,
während die Datei geöffnet ist, ist im Fat-Eintrag die falsche (zu
kleine) Dateigröße vermerkt und Dir gehen diejenigen Logzeilen verloren,
die seit dem letzten "myFile.close();" geschrieben wurden.
Danke für die ausführlichen Hinweise Jürgen. Hab das auch soweit
verstanden denke ich. Aber würde das nicht bedeuten ich müsste die
Datensätze einer ganzen Minute (also 60) zwischenspeichern um sie dann
mit einem mal auf die SD zu schreiben?
Oder würde das auch über eine Zählschleife funktionieren? z.B. so :
-jede Sekunde wie bisher Daten speichern
aber das "myFile.close();" durch folgende Schleife ersetzen:
Aber vielleicht gleich mal noch eine andere Frage. Wenn ich die (zurzeit
auskommentierte Sleepfunktion (1 Sekunde) benutze, gibt er mir
komischerweise mehrere Datensätze mit der selben Uhrzeit aus bis er zur
nächsten Sekunde kommt und dann wieder mehrmals diese Uhrzeit ausspuckt.
Ich kapier bloß nicht warum, da ja eigentlich die Funktion den
Controller in den PowerDown versetzt und somit nur durch einen externen
Interrupt oder eben den WDT gewckt werden dürfte. Mir scheint es aber
so, als ob er mehrfach geweckt wird, wüßte bloß nicht durch was. HAt
jemand vielleicht dazu auch noch eine Idee?
mit dem Delay funktioniert es ja nun alles, wie es soll. Aber da es sich
um einen akkubetriebenen Datenlogger handeln soll, währe ein
funktionerende Sleepfunktion natürlich um welten besser! :(
gruß Vwirt
Vwirt schrieb:> Danke für die ausführlichen Hinweise Jürgen. Hab das auch soweit> verstanden denke ich. Aber würde das nicht bedeuten ich müsste die> Datensätze einer ganzen Minute (also 60) zwischenspeichern um sie dann> mit einem mal auf die SD zu schreiben?
Nein, es muss nichts zwischengespeichert werden.
Du müßtest die Datei eben nur nicht nach jeder Datenzeile schließen,
sondern nur dann, wenn seit dem letzten Schließen der Datei mindestens
60 Sekunden vergangen sind.
>> Oder würde das auch über eine Zählschleife funktionieren? z.B. so :
Ich würde die Zählschleife basierend auf dem Stand des
Millisekundenzählers realisieren. Und selbstverständlich muß die Datei
auch nach dem Schließen gleich wieder zum Schreiben geöffnet werden.
Ich würde einfach Deine bisherige Logik zum Öffnen der Datei
1
myFile=SD.open("test.txt",FILE_WRITE);
durch diesen Code ersetzen:
1
staticunsignedlonglastOpened=0;// statisch, nur einmalig initialisiert!
Dadurch wird eine länger als 60 Sekunden geöffnete Datei zuerst mal
geschlossen, und danach wird die Datei geöffnet, falls sie nicht
geschlossen ist.
Der bisherige close-Befehl nach dem Ausgeben der Daten muss dann
gelöscht werden, sonst wird die Datei weiterhin nach jedem Schreiben
geschlossen.