CSV Daten vom Arduino Datenlogger übertragen

Hallo

Ich habe Datenlogger gebaut, der derzeit die Daten auf eine SD-Karte speichert.

Jetzt möchte ich die Daten ins Netz bringen bzw. verschicken oder laufend übertragen.

Der Logger ist Mobil und der Standort wechselt oft.

In welche Richtung muss ich mich orientieren bzw. mit welchem Shield oder welcher Technik komme ich zum Ziel. Derzeit Versuche ich es mit 1Sheeeld, aber wenn die Bluetooth Verbindung mal kurz unterbrochen wird, sind die Daten dazwischen weg.

Vielleicht kann mir jemand die Richtung weisen wie ich das realisieren kann.

Luggi: ..... Vielleicht kann mir jemand die Richtung weisen wie ich das realisieren kann.

Dann nimm doch WLan mit einem Wemos D1 mini oder NodeMCU.

Wow
Danke Dieter für die rasche Antwort

Da muss ich wohl noch etwas ausholen.

Ich beschäftige mich erst seit Jänner mit dem Arduino.

Ich Messe an verschiedenen Orten zwei analoge Sensoren aus, die Sensordaten speichere
ich alle 60 sek. bzw. auch nach jeweils 10 cm Weg der von einem Drehgeber gemessen wird.

Die Daten werden auf einer SD -Karte mit Datum und Uhrzeit gespeichert und zugleich auf einem Display angezeigt.

Um nicht immer die SD-Karte auslesen zu müssen, suche ich nach einer möglichkeit die SD-Karte auszulesen und die Daten zu verschicken bzw. die Daten im Messbetrieb zu übertragen und zugleich
irgendwo abzuspeichern, um danach in einem Diagramm dargestellt zu werden.

Die Grundfunktion, speichern auf SD und anzeigen auf LCD soll dabei beibehalten werden.
Es stehen 12V Spannung zur Verfügung, anonsten ist der Logger in der Wildnis.

Von dem Wemos D1 mini oder NodeMCU habe ich noch nie gehört.

Mit welchem der beiden Shields komme ich eher zu Ziel und was ist dafür alles erforderlich.
Ich muss ja irgendwie eine Verbindung zum Internet herstellen. Brauche ich da ein Internetmodem
oder geht auch zum Beispiel ein Smartphone.

Ich Danke dir auf jeden Fall schon für deine Antwort

Hier mein Code

#include <SD.h>
#include <SPI.h>
#include "RTClib.h"
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>

#define I2C_ADDR    0x27 // Define I2C Address where the PCF8574A is
#define BACKLIGHT_PIN     3
#define En_pin  2
#define Rw_pin  1
#define Rs_pin  0
#define D4_pin  4
#define D5_pin  5
#define D6_pin  6
#define D7_pin  7
#define outputA 6 
#define outputB 7

int n = 1;

int var3 = 0;         // counter
int var1 = 0;         // Druckgeber 1 
int var2 = 0;         // Druckgeber 2 
int Pressensensor = 0;     // Potipin fuer Demo
int Getriebesensor = 1;     // Potipin fuer Demo
float counter = 0;    // float fuer Kommastellen int fuer ganze Zahlen
float Vortriebsstrecke = 0; 

LiquidCrystal_I2C  lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin);

RTC_DS1307 rtc;    

//Definiere Prototypen
void speichernAufSD(void);

#define outputA 6
#define outputB 7

int aState;
int aLastState;

const int chipSelect = 4;
unsigned long timer;
const unsigned int speicherZyklus = 60000; //Speichern alle 60 Sekunden



void setup() {

    /* Start communication. */
  OneSheeld.begin();
  
  Serial.begin(115200);
  pinMode(SS, OUTPUT);
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }
  while (!Serial) {
  }
  Serial.print("Initializing SD card...");
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    while (1);
  }
  Serial.println("card initialized.");
  if (! rtc.isrunning()) {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
  }
  pinMode(Pressensensor, INPUT);
  pinMode(Getriebesensor, INPUT);
  pinMode(outputA, INPUT);
  pinMode(outputB, INPUT);

  timer = millis(); //Startwert von timer

    lcd.begin (20,4);
  
// Switch on the backlight
  lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE);
  lcd.setBacklight(HIGH);
  lcd.setCursor ( 0, 0 );                  
  lcd.print("BOHRDATENLOGGER");
  lcd.setCursor ( 0, 1 );        // go to the next line         
  lcd.print("Vortrieb m/t:");
  lcd.setCursor ( 0, 2 );        // go to the next line
  lcd.print("Vortrieb bar:");  
  lcd.setCursor ( 0, 3 );        // go to the next line
  lcd.print("Getriebe bar:");

}

void loop(){
  {
  lcd.setCursor ( 15, 1 );
  Vortriebsstrecke = counter * 0.05;
  var1 = analogRead(Pressensensor);
  var1 = map(var1, 0, 1000, 0, 400);
  var2 = analogRead(Getriebesensor);
  var2 = map(var2, 0, 1000, 0, 400);
  
  lcd.print(Vortriebsstrecke); 
  lcd.setCursor ( 15, 2 );        // go to the next line
  lcd.print(var1);
  lcd.print(' ');
  lcd.setCursor ( 15, 3 );
  lcd.print(var2);
  lcd.print(' ');
  
}

  aState = digitalRead(outputA); // Reads the "current" state of the outputA
  // If the previous and the current state of the outputA are different, that means a Pulse has occured
  if (aState != aLastState)
  {
    // If the outputB state is different to the outputA state, that means the encoder is rotating clockwise
    if (digitalRead(outputB) != aState)
    {
      counter ++;
    }// else       
    {
      //counter --;
    }
    speichernAufSD();
    aLastState = aState; // Updates the previous state of the outputA with the current state
  }

  //Hier wird nun im Zyklus von "speicherZyklus" das Unterprogramm "speichernAufSD()" aufgerufen
  if (millis() >= timer + speicherZyklus)
  {
    timer = millis();
    speichernAufSD();
    
  }
}


void speichernAufSD()
{

  DateTime now = rtc.now();

  if (now.day() < 10) {
    Serial.print('0');
  }
  Serial.print(now.day(), DEC);
  Serial.print('/');
  if (now.month() < 10) {
    Serial.print('0');
  }
  Serial.print(now.month(), DEC);
  Serial.print('/');
  Serial.print(now.year(), DEC);
  Serial.print(",  ");
  if (now.hour() < 10) {
    Serial.print('0');
  }
  Serial.print(now.hour(), DEC);
  Serial.print(':');
  if (now.minute() < 10) {
    Serial.print('0');
  }
  Serial.print(now.minute(), DEC);
  Serial.print(':');
  if (now.second() < 10) {
    Serial.print('0');
  }
  Serial.print(now.second(), DEC);
  Serial.print(',');


  Serial.print(var1);
  Serial.print(",  ");
  Serial.print(var2);
  Serial.print(",  ");
  Serial.println(counter * 0.05);


  File dataFile = SD.open("datalog.txt", FILE_WRITE);

  // if the file is available, write to it:
  if (dataFile) {


    if (now.day() < 10) {
      dataFile.print('0');
    }
    dataFile.print(now.day(), DEC);
    dataFile.print('/');
    if (now.month() < 10) {
      dataFile.print('0');
    }
    dataFile.print(now.month(), DEC);
    dataFile.print('/');
    dataFile.print(now.year(), DEC);
    dataFile.print(",");
    if (now.hour() < 10) {
      dataFile.print('0');
    }
    dataFile.print(now.hour(), DEC);
    dataFile.print(':');
    if (now.minute() < 10) {
      dataFile.print('0');
    }
    dataFile.print(now.minute(), DEC);
    dataFile.print(':');
    if (now.second() < 10) {
      dataFile.print('0');
    }
    dataFile.print(now.second(), DEC);
    dataFile.print(",");

    dataFile.print(var1);
    dataFile.print(",  ");
    dataFile.print(var2);
    dataFile.print(",  ");
    dataFile.print(counter * 0.05);
    dataFile.println();

    dataFile.close();
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening datalog.txt");
  }
}

Du kannst also entweder Deinen ganzen Sketch auf den WEMOS umbauen (Achtung, der läuft mit 3,3V - Pegelwandler benutzen), das hätte den Vorteil, dass der direkt auf die SD zugreifen kann. Oder Du bindest den WEMOS per I2C an den Arduino (Pegelwandler), dann kann Dein bisheriger Sketch bleiben, der Arduino müsste dann nur auf Anforderung die Anzahl der Bytes auf der SD-Card liefern und dann die Bytes in handlichen Blöcken.

Sowas nachträglich einzubauen ist immer ungünstiger, als wenn das von Anfang an geplant wird. Ich gehe davon aus, dass das Übertragen der Daten erfolgt, wenn keine Messung läuft. Weiterhin müssen dann auch noch Aktionen zum Löschen der Datei erfolgen.

Ich weiß nicht, wie voll der Arduino schon ist. Das dürfte wohl entscheidend sein.

Gruß Tommy

Mein Arduino ist mit 55% belegt.
Bei Bedarf baue ich alles neu auf. Meine Sensoren Arbeiten mit 5 Volt, die würde ich auch gerne weiter verwenden, da einer ca 250.- kostet. (Drucksensor bis 600bar)

Alles andere würde ich mir gleich neu anschaffen und dann versuchen wie beim ersten Logger nach und nach zum Laufen bringen. Da hab ich auch klein begonnen.
Erst serial monitor, danach Speichern auf SD, dann LCD. Dann muss auch die Übertragung zu schaffen sein.

Ich finde es überwältigend, das ihr Profis eurer Wissen auf diesem Wege auch Anfängern zur Verfügung stellt. Ich bedanke mich recht herzlich dafür.

Anbei noch ein paar Fotos von meinem Logger.

Jetzt brauche ich noch eine Einkaufsliste, dann könnte ich shoppen gehen, ein Huawei E5577Cs-321 Modem steht mir zur Verfügung. Alles andere kann ich neu konzipieren.

Vielen Dank!

Wie sind die Sensoren angebunden? Was heißt 55%? RAM oder Flash?

Gruß Tommy

Die Sensoren werden mit 5V versorgt und haben einen Ausgang von 0 - 5 volt angeschlossen auf A0 + A1 am Uno.

Das bekomme ich nach dem kompilieren? In wie weit er sonst ausgelastet ist weiß ich nicht.

Der Sketch verwendet 17766 Bytes (55%) des Programmspeicherplatzes. Das Maximum sind 32256 Bytes. Globale Variablen verwenden 1330 Bytes (64%) des dynamischen Speichers, 718 Bytes für lokale Variablen verbleiben.

Die Daten die ich übertragen will sehen wie folgt aus.

Initializing SD card...card initialized. 03/08/2018, 16:07:04, 28, 63, 0.00 03/08/2018, 16:07:07, 25, 60, 0.05 03/08/2018, 16:07:13, 30, 65, 0.10 03/08/2018, 16:07:14, 41, 75, 0.10 03/08/2018, 16:07:16, 33, 64, 0.15 03/08/2018, 16:07:20, 47, 80, 0.20

bis zu 1100 Datensätze pro Tag sind möglich

Naja, die 64% RAM nähern sich schon bald der kritischen Grenze.

Also ich würde Dir vorschlagen es mit dem WEMOS D1 mini pro (ESP8266) neu aufzubauen. Den kannst Du genau so in der Arduino-IDE programmieren, wie die anderen Arduinos.

Die Sensoren über einen externen ADC mit I2C-Ausgang an den ESP ankoppeln, da der ESP8266 nur 1 analogen Eingang bis 3,3 V hat. Die SD kannst Du direkt anschalten, da war letztens hier eine Anleitung.

Dann noch 1 Eingang, der zwischen Messbetrieb und Sendebetrieb umschaltet.

Du könntest zwar auch den ESP32 nutzen, der hat mehrere analoge Eingänge, diese aber auch nur bis 3,3V.

Gruß Tommy

Edit: z.B. So etwas als ADC und dann noch einen I2C Pegelwandler von 5V auf 3,3V für den Anschluss am ESP8266.

Edit2: So könntest Du einen Micro-USB-Adapter direkt verdrahten (bis runter lesen)

Theoretisch möglich aber praktisch würde ich der internen Logik moderner SD-Karten bei der Verteilung mehr trauen, als dem direkten Schreiben in den Flash und er hat als Notlösung immer noch die Möglichleit, die Karte am PC zu lesen.

Gruß Tommy

Danke für Eure Hinweise! (Gestern mußte ich Leider weg, ein erschöpfter Kletterer mußte aus einem Klettersteig gerettet werden)

Ich hab mir heute den Wemos d1 mini pro + wemos sd shield + ADS1115 bestellt.

Mal sehen wie weit ich mit den Umbauten ohne Hilfe komme, ich hoffe ich darf mich bei Euch wieder melden wenn ich mit meiner Weißheit am Ende bin.

Vielen Dank erst mal, und schöne Grüße aus Rauris.

Hallo zusammen das bin ich wieder, leider schneller als gehofft.

Ich hab mir die Teile besorgt und versucht meinen Code darauf laufen zu lassen.

Ich habe einen Wemos D1 mini pro und ein SD-Shield mit RTC.

Ich hab die LCD im Code mal ausgeklammert, aber auch ohne der LCD bekomme ich auf dem Serial Monitor nicht das was ich sehen möchte.
Die SD - Karte wird zwar erkannt, aber es wird darauf nichts geschrieben.

Im Serial wird folgendes angezeigt.

<
Initializing SD card…card in⸮
ets Jan 8 2013,rst cause:4, boot mode:(3,6)

wdt reset
load 0x4010f000, len 1384, room 16
tail 8
chksum 0x2d
csum 0x2d
vbb28d4a3
~ld

Nehme ich die SD heraus dann steht im Serial

<
Initializing SD card…Card failed, or not present

Soft WDT reset

ctx: cont
sp: 3ffffd90 end: 3fffffd0 offset: 01b0

stack>>>
3fffff40: 3fffdad0 0000001b 3ffeeca0 40205580
3fffff50: 3fffdad0 3ffee884 3ffeeca0 402056c9
3fffff60: 3ffe8a50 003d0900 3ffeeb24 402056c9
3fffff70: 3ffe898c 00000001 3ffeeca0 402056f4
3fffff80: 3fffdad0 3ffee884 3ffeeca0 40205718
3fffff90: feefeffe 3ffee884 3ffeeca0 40202c64
3fffffa0: feefeffe feefeffe feefeffe feefeffe
3fffffb0: feefeffe 00000000 3ffeecd4 40205d44
3fffffc0: feefeffe feefeffe 3ffe85f0 40100739
<<<stack<<<

ets Jan 8 2013,rst cause:4, boot mode:(3,6)

wdt reset
load 0x4010f000, len 1384, room 16
tail 8
chksum 0x2d
csum 0x2d
vbb28d4a3
~ld

Ich glaube das mein Code so nicht kompatibel ist und ich wieder von neuem beginnen muss?

Kann mir jemand sagen:
Kann ich meinen Code verwenden?
Wenn ja, in welchem Bereich muss ich was umbauen?

Ich komme der zeit nicht weiter weil ich nicht weiß wo ich suchen soll.
Danke erst mal.

Hier nochmal mein Code.

#include <SD.h>
#include <SPI.h>
#include "RTClib.h"
#include <Wire.h> 

/*#include <LiquidCrystal_I2C.h>


#define I2C_ADDR    0x27 // Define I2C Address where the PCF8574A is
#define BACKLIGHT_PIN     3
#define En_pin  2
#define Rw_pin  1
#define Rs_pin  0
#define D4_pin  4
#define D5_pin  5
#define D6_pin  6
#define D7_pin  7
#define outputA 6 
#define outputB 7*/

int n = 1;

int var3 = 0;         // counter
int var1 = 0;         // Druckgeber 1 Presszylinder
int var2 = 0;         // Druckgeber 2 Getriebedruck
int Pressensensor = 0;     // Potipin fuer Demo
int Getriebesensor = 1;     // Potipin fuer Demo
float counter = 0;    // float fuer Kommastellen int fuer ganze Zahlen
float Vortriebsstrecke = 0; 

//LiquidCrystal_I2C  lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin);

RTC_DS1307 rtc;    


//Definiere Prototypen
void speichernAufSD(void);

#define outputA 6
#define outputB 7


int aState;
int aLastState;

const int chipSelect = 4;
unsigned long timer;
const unsigned int speicherZyklus = 5000; //Speichern alle 5 Sekunden





void setup() {

  Serial.begin(115200);
  pinMode(SS, OUTPUT);
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }
  while (!Serial) {
  }
  Serial.print("Initializing SD card...");
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    while (1);
  }
  Serial.println("card initialized.");
  if (! rtc.isrunning()) {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
  }
  pinMode(Pressensensor, INPUT);
  pinMode(Getriebesensor, INPUT);
  pinMode(outputA, INPUT);
  pinMode(outputB, INPUT);

  timer = millis(); //Startwert von timer

    /*lcd.begin (20,4);
  
// Switch on the backlight
  lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE);
  lcd.setBacklight(HIGH);
  lcd.setCursor ( 0, 0 );                  
  lcd.print("   BOHRDATENLOGGER  ");
  lcd.setCursor ( 0, 1 );        // go to the next line         
  lcd.print("Vortrieb m/t:");
  lcd.setCursor ( 0, 2 );        // go to the next line
  lcd.print("Vortrieb bar:");  
  lcd.setCursor ( 0, 3 );        // go to the next line
  lcd.print("Getriebe bar:");*/

}


void loop(){
  /*{
  lcd.setCursor ( 15, 1 );
  Vortriebsstrecke = counter * 0.05;
  var1 = analogRead(Pressensensor);
  var1 = map(var1, 0, 1000, 0, 400);
  var2 = analogRead(Getriebesensor);
  var2 = map(var2, 0, 1000, 0, 400);
  
  lcd.print(Vortriebsstrecke); 
  lcd.setCursor ( 15, 2 );        // go to the next line
  lcd.print(var1);
  lcd.print(' ');
  lcd.setCursor ( 15, 3 );
  lcd.print(var2);
  lcd.print(' ');
  
}*/

  aState = digitalRead(outputA); // Reads the "current" state of the outputA
  // If the previous and the current state of the outputA are different, that means a Pulse has occured
  if (aState != aLastState)
  {
    // If the outputB state is different to the outputA state, that means the encoder is rotating clockwise
    if (digitalRead(outputB) != aState)
    {
      counter ++;
    }// else       
    {
      //counter --;
    }
    speichernAufSD();
    aLastState = aState; // Updates the previous state of the outputA with the current state
  }

  //Hier wird nun im Zyklus von "speicherZyklus" das Unterprogramm "speichernAufSD()" aufgerufen
  if (millis() >= timer + speicherZyklus)
  {
    timer = millis();
    speichernAufSD();
    
  }
}



void speichernAufSD()
{

  DateTime now = rtc.now();

  if (now.day() < 10) {
    Serial.print('0');
  }
  Serial.print(now.day(), DEC);
  Serial.print('/');
  if (now.month() < 10) {
    Serial.print('0');
  }
  Serial.print(now.month(), DEC);
  Serial.print('/');
  Serial.print(now.year(), DEC);
  Serial.print(",  ");
  if (now.hour() < 10) {
    Serial.print('0');
  }
  Serial.print(now.hour(), DEC);
  Serial.print(':');
  if (now.minute() < 10) {
    Serial.print('0');
  }
  Serial.print(now.minute(), DEC);
  Serial.print(':');
  if (now.second() < 10) {
    Serial.print('0');
  }
  Serial.print(now.second(), DEC);
  Serial.print(',');


  Serial.print(var1);
  Serial.print(",  ");
  Serial.print(var2);
  Serial.print(",  ");
  Serial.println(counter * 0.05);


  File dataFile = SD.open("datalog.txt", FILE_WRITE);

  // if the file is available, write to it:
  if (dataFile) {



    if (now.day() < 10) {
      dataFile.print('0');
    }
    dataFile.print(now.day(), DEC);
    dataFile.print('/');
    if (now.month() < 10) {
      dataFile.print('0');
    }
    dataFile.print(now.month(), DEC);
    dataFile.print('/');
    dataFile.print(now.year(), DEC);
    dataFile.print(",");
    if (now.hour() < 10) {
      dataFile.print('0');
    }
    dataFile.print(now.hour(), DEC);
    dataFile.print(':');
    if (now.minute() < 10) {
      dataFile.print('0');
    }
    dataFile.print(now.minute(), DEC);
    dataFile.print(':');
    if (now.second() < 10) {
      dataFile.print('0');
    }
    dataFile.print(now.second(), DEC);
    dataFile.print(",");

    dataFile.print(var1);
    dataFile.print(",  ");
    dataFile.print(var2);
    dataFile.print(",  ");
    dataFile.print(counter * 0.05);
    dataFile.println();

    dataFile.close();
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening datalog.txt");
  }
}

Hallo Zusammen!
Hallo Tommy!

Ich hab meinen Code soweit am Wemos das Serial, LCD und speichern auf SD funktioniert.

Leider habe ich Probleme mit dem counter.
Ich verwende zum testen einen Drehgeber (hat mit dem Uno auch funktioniert), in Echt sind dann zwei kontaktlose Näherungsschalter für die Wegsignale zuständig.

Die Signale sollen dann nach einem bestimmten Weg, das Speichern der Parameter auslösen,
zusätzlich zu den zeitabhängigen Speicherpunkte.

Auf welche Pins beim Wemos kann ich die Signale anschließen?

Siehe Bilder meiner Verkabelung

IMG_3674.JPG

IMG_3675.JPG

Hallo!

Ich konnte die Pins finden. Ich habe am Wemos D0 + D3 benutzt.

Im Code sind sie dann mit Pin 0 + 16 definiert.