DATA logger

Toon hier Uw afgeronde projecten aan anderen.
Berichten: 88
Geregistreerd: 16 Jul 2015, 21:02

DATA logger

Berichtdoor wim2584 » 28 Nov 2020, 21:45

hieronder een Data logger, 2x temperatuur DS18B20 , 2 x temperatuur MAX6675 (K koppel), 1 x DHT (temperatuur + vocht), 1x 0-5 Vdc , 1 x 0-50 Vdc, 1 x 0-250Vac , met real power, CosQ en real ampere.
met een 4 standen schakelaar is de logtijd instelbaar:

A B
1 1 = 1 sec
0 1 = 10 sec
1 0 = 1 min
0 0 = 10 min

voor de ingang van de dc spanningsmeting heb ik een opamp gebruikt , dit om ingang te beschermen tegen te hoge ingangs spanning of verkeerde polariteit, als extra heb ik tussen uitgang opamp en ingang arduino een 10k weerstand opgenomen (met dank aan Koepel), hierdoor wordt de ingangsstroom nooit hoger dan 1 mA (de arduino kan hier net tegen).

voor de ac spanning meting heb ik de module : ZMPT101B gebruikt, 0-250 Vac in, uit sinus 0-5 volt met "0"spanning 2,5 volt.
voor de ac stroom heb ik een stroomtrafo gebruikt die ik "nog had liggen", geeft nu middelpunt 2,5 V (middenpunt twee weerstanden 10 k tussen 0 em 5 volt) , en in: 0- 16 A uit: sinus 0-5 volt met "0"spanning 2,5 volt.

met bovenstaande redelijk nauwkeurig power te meten (< 5%) spanning en stroom en cos Q

de code verdiend geen schoonheids prijs, ik ben niet de handigste met programmeren.... maar werkt wel goed,

opmerking :de hele loop void (met wegschrijven naar SD card) duurt best wel lang, daarom geen snellere logging dan +- 1 sec mogelijk, (wie weet waar dit aan ligt?? ik hou me aanbevolen!!)

voor de waardes op display te zetten, een 20x4 LCD

Groet Wim,

Code: Alles selecteren
#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include "RTClib.h"
unsigned long Timer0;
unsigned long Timer1;
unsigned long Timer2;
unsigned long Timer3;
unsigned long Timer4;
unsigned long Timer5;
float koppelA;
float koppelB;
float ds18b20A;
float ds18b20B;

int serial ; // keuze mogelijkheid serial print of niet (keuse is begin loop)

//voltmeters
int analogInputA = A1;
float vinA = 0.0;
int analogInputB = A2;
float vinB = 0.0;

// keuze log intervaltijd
int knopA;
int knopB;
long logtijd;

// dht sensor
#include "DHT.h"
float h;
float t;
DHT dht(9, DHT22);

//DS18B20
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 8
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

//MAX6675 thermocouple
#include <max6675.h>
//thermoCLK, thermoCS, thermoDO
int thermoDO = 5;
int thermoCLK = 4;
int thermoCSA = 7;
int thermoCSB = 6;
int welke = true; // om de beurt uitlezen , zelfde clk en do pin, alleen cs is verschillend

MAX6675 thermocoupleA(thermoCLK, thermoCSA, thermoDO);
MAX6675 thermocoupleB(thermoCLK, thermoCSB, thermoDO);

// power en Vrms Irms en CosQ
#include "EmonLib.h"             // Include Emon Library
EnergyMonitor emon1;             // Create an instance

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4); // set the LCD address to 0x27 for a 16 chars and 2 line display

RTC_DS1307 RTC; // define the Real Time Clock object
const int chipSelect = 10;

// the logging file
File logfile;

void error(char *str)
{
  Serial.print("error: ");
  Serial.println(str);

  while (1);
}

void setup(void)
{
  // power en Vrms Irms en CosQ
  {
    Serial.begin(9600);
    emon1.voltage(A3, 330, -1.7);  // Voltage: input pin, calibration, phase_shift (callibration 19-11-2020)
    emon1.current(A0, 10.00);      // Current: input pin, calibration.(callibration 19-11-2020)
  }

  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);

  sensors.begin(); //ds18B20

  lcd.init();                      // initialize the lcd
  lcd.backlight();

  Serial.begin(9600);

  Serial.println();

  // initialize the SD card
  Serial.print(F("Initializing SD card..."));
  // make sure that the default chip select pin is set to
  // output, even if you don't use it:
  pinMode(10, OUTPUT);

  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    lcd.setCursor(0, 1);
    lcd.print(F("SD CARD : FOUT "));
    lcd.setCursor(0, 0);
    error("Card failed, or not present");
  }
  Serial.println(F("card initialized."));
  lcd.setCursor(0, 1);
  lcd.print(F("SD CARD : ok "));


  DateTime now = RTC.now();
  lcd.setCursor(2, 2);
  lcd.print(now.day(), DEC);
  lcd.print("-");
  lcd.print(now.month(), DEC);
  lcd.print("-");
  lcd.print(now.year(), DEC);
  lcd.print(" ");
  lcd.setCursor (13, 2);
  lcd.print(now.hour(), DEC);
  lcd.print((":"));
  if (now.minute() < 10) {
    lcd.setCursor(16, 2);
    lcd.print("0");
    lcd.setCursor(17, 2);
    lcd.print(now.minute(), DEC);
  } else {
    lcd.print(now.minute(), DEC);
  }
  lcd.setCursor(2, 0);
  lcd.print(F("DATA-LOGGER   "));
  lcd.setCursor(0, 1);
  lcd.print(F("  V 1.3       "));
  lcd.setCursor(1, 3);
  lcd.print(F("W Lemson  nov-2020  "));
  delay(5000);


  // create a new file
  char filename[] = "LOGGER00.CSV";
  for (uint8_t i = 0; i < 100; i++) {
    filename[6] = i / 10 + '0';
    filename[7] = i % 10 + '0';
    if (! SD.exists(filename)) {
      // only open a new file if it doesn't exist
      logfile = SD.open(filename, FILE_WRITE);
      break;  // leave the loop!
    }
  }

  if (! logfile) {

    lcd.setCursor(0, 1);
    lcd.print(F("SD CARD : FOUT      "));
    lcd.setCursor(0, 0);
    error("couldnt create file");
  }

  Serial.print(F("Logging to: "));
  Serial.println(filename);

  // connect to RTC
  Wire.begin();
  if (!RTC.begin()) {
    logfile.println("RTC failed");
    Serial.println(F("RTC failed"));
  }
  logfile.println(F("datum,tijd ,ch1,ch2,ch3,ch4,ch5,ch6,temperatuur,vocht,ac RMSvolt,RMSstroom,cosQ,realpower,apparentPower"));

  Serial.println(F("datum,tijd,ch1,ch2,ch3,ch4,ch5,ch6,temperatuur,vocht,ac RMSvolt,RMSstroom,cosQ,realpower,apparentPower"));

  lcd.setCursor(0, 0);
  lcd.print(F("                                    "));
  lcd.setCursor(0, 1);
  lcd.print(F("                                    "));
  lcd.setCursor(0, 2);
  lcd.print(F("                                    "));
  lcd.setCursor(0, 3);
  lcd.print(F("                                    "));

  //rij 1
  lcd.setCursor(0, 0);
  lcd.print("1");
  lcd.setCursor(1, 0);
  lcd.print(":");
  lcd.setCursor(6, 0 );
  lcd.print("C");
  lcd.setCursor(8, 0);
  lcd.print("5");
  lcd.setCursor(9, 0);
  lcd.print(":");
  lcd.setCursor(14, 0 );
  lcd.print("V");
  lcd.setCursor(19, 0 );
  lcd.print("C");

  //rij 2
  lcd.setCursor(0, 1);
  lcd.print("2");
  lcd.setCursor(1, 1);
  lcd.print(":");
  lcd.setCursor(6, 1);
  lcd.print("C");
  lcd.setCursor(8, 1);
  lcd.print("6");
  lcd.setCursor(9, 1);
  lcd.print(":");
  lcd.setCursor(14, 1 );
  lcd.print("V");
  lcd.setCursor(19, 1 );
  lcd.print("%");


  //rij 3
  lcd.setCursor(0, 2);
  lcd.print("3");
  lcd.setCursor(1, 2);
  lcd.print(":");
  lcd.setCursor(6, 2 );
  lcd.print("C");
  lcd.setCursor(8, 2);
  lcd.print("7");
  lcd.setCursor(9, 2);
  lcd.print(":");
  lcd.setCursor(13, 2 );
  lcd.print("V");


  //rij 4
  lcd.setCursor(0, 3);
  lcd.print("4");
  lcd.setCursor(1, 3);
  lcd.print(":");
  lcd.setCursor(2, 3 );
  lcd.setCursor(6, 3 );
  lcd.print("C");


  Timer0 = millis();
  Timer1 = millis();
  Timer2 = millis();
  Timer3 = millis();
  Timer4 = millis();
  Timer5 = millis();
  delay(10);
}


void loop(void)


{
  DateTime now;
  now = RTC.now();

  serial = LOW; // serial print = HIGH / niet serial print = LOW

  knopA = digitalRead(2);
  knopB = digitalRead(3);

  lcd.backlight();

  // power en Vrms Irms en CosQ

  emon1.calcVI(20, 2000);        // Calculate all. No.of half wavelengths (crossings), time-out
  float realPower       = emon1.realPower;        //extract Real Power into variable
  float apparentPower   = emon1.apparentPower;    //extract Apparent Power into variable
  float powerFActor     = emon1.powerFactor;      //extract Power Factor into Variable
  float supplyVoltage   = emon1.Vrms;             //extract Vrms into Variable
  float Irms            = emon1.Irms;             //extract Irms into Variable

  //DC voltmeting

  vinA = ((analogRead(analogInputA) * 5.0) / 1024) * 10.34; //value* 5volt /1024 dan maal correctie factor voor juiste uitlezing(callibration 19-11-2020)

  if (vinA < 0.4) {
    vinA = 0.0; //statement to quash undesired reading !
  }
  vinB = ((analogRead(analogInputB) * 5.00  ) / 1024) * 1.055; //value* 5volt /1024 dan maal correctie factor voor juiste uitlezing(callibration 19-11-2020)

  if (vinB < 0.09) {
    vinB = 0.0; //statement to quash undesired reading !

  }

  sensors.requestTemperatures(); // Send the command to get temperatures
  //dht + ds18b20+koppels
  dht.begin();
  if (millis() - Timer3 > 10 ) {
    Timer3 = millis();
    h = (dht.readHumidity()) ;
    t = dht.readTemperature() - 2.5, 1;
    ds18b20A = sensors.getTempCByIndex(0);
    ds18b20B = sensors.getTempCByIndex(1);
  }

  //uitlezen twee K oppel modules, MAX6675, min. sampletijd 200 mS, om de beurt uitlezen

  if (welke == true)  {
    koppelA = (thermocoupleA.readCelsius() - 2); // thermocoupleA reading - correctie(callibration 19-11-2020)
    if ( millis() - Timer5 > 200) {
      welke = false;
      Timer5 = millis();
    }
  }
  else if (welke == false )  {
    koppelB = (thermocoupleB.readCelsius() - 2); // thermocoupleB reading - correctie(callibration 19-11-2020)
    if ( millis() - Timer5 > 200) {
      welke = true;
      Timer5 = millis();
    }
  }

  //sample tijd

  if (millis() - Timer1 >= 250 ) { // tijd tussen de samples in msec op display
    Timer1 = millis();

    //rij 1
    lcd.setCursor(2, 0 );

    if (ds18b20A < -100) {
      lcd.print("nan ");
    } else if  (ds18b20A < 100) {
      lcd.print(ds18b20A, 1);
    } else {
      lcd.print(ds18b20B, 0);
    }
    lcd.setCursor(6, 0 );
    lcd.setCursor(10, 0 );
    lcd.print(vinB, 2);
    lcd.setCursor(16, 0);
    lcd.print(t, 0);

    //rij 2
    lcd.setCursor(2, 1 );
    if (ds18b20B < -100) {
      lcd.print("nan ");
    } else if (ds18b20B < 100) {
      lcd.print(ds18b20B, 1);
    } else {
      lcd.print(ds18b20B, 0);
    }

    lcd.setCursor(10, 1 );
    lcd.print("    ");
    lcd.setCursor(10, 1 );
    lcd.print(vinA, 1);
    lcd.setCursor(16, 1);
    lcd.print(h, 0);

    //rij 3
    lcd.setCursor(2, 2 );
    lcd.print("    ");
    lcd.setCursor(2, 2 );
    if (koppelA < 100) {
      lcd.print(koppelA, 1);
    } else {
      lcd.print(koppelA, 0);
    }
    lcd.setCursor(6, 2 );
    lcd.print("C");
    lcd.setCursor(10, 2 );
    lcd.print("   ");
    lcd.setCursor(10, 2 );
    if (supplyVoltage < 5) {
      lcd.print("000");
    } else {
      lcd.print(supplyVoltage, 0);
    }
    lcd.setCursor(13, 2 );
    lcd.print("V");
    lcd.setCursor(19, 2);
    lcd.print("Q");
    lcd.setCursor(15, 2);
    if (Irms < 0.05) {
      lcd.print("0.0");
    } else {
      lcd.print(powerFActor, 1);
    }

    //rij 4

    lcd.setCursor(2, 3 );
    lcd.print("    ");
    lcd.setCursor(2, 3 );
    if (koppelB < 100) {
      lcd.print(koppelB, 1);
    } else {
      lcd.print(koppelB, 0);
    }
    lcd.setCursor(9, 3);

    if (realPower < 5) {
      lcd.print("000");
    } else {
      lcd.print("    ");
      lcd.setCursor(9, 3);
      lcd.print(realPower, 0);
    }
    lcd.setCursor(13, 3);
    lcd.print("W");
    lcd.setCursor(15, 3);
    if (Irms < 0.05) {
      lcd.print("0.00");
    } else {
      lcd.print(Irms, 1);
    }
    lcd.setCursor(19, 3);
    lcd.print("A");
  }

  // keuze log tijd
  if (serial == HIGH) {
    Serial.print (digitalRead(2));
    Serial.println (digitalRead(3));
  }


  if (knopA == HIGH && knopB == HIGH) {
    if (millis() - Timer4 >= 100 ) { //stabiliseertijd
      Timer1 = millis();
      logtijd = 10;// tijd tussen de samples in msec blijkt in praktijk ongeveer 1 sec te zijn, korter is totale code niet?? (misschien oplossen in toekomst?)
    }
  } else

    if (knopA == HIGH && knopB == LOW) {
      if (millis() - Timer4 >= 100 ) {//stabiliseertijd
        Timer1 = millis();
        logtijd = 10000;// tijd tussen de samples in msec
      }


    } else if (knopA == LOW && knopB == HIGH) {
      if (millis() - Timer4 >= 100 ) { //stabiliseertijd
        Timer1 = millis();
        logtijd = 60000;// tijd tussen de samples in msec
      }
    }
    else if (knopA == LOW && knopB == LOW) {
      if (millis() - Timer4 >= 100 ) { //stabiliseertijd
        Timer1 = millis();
        logtijd = 3600000;// tijd tussen de samples in msec
      }
    }
  if (serial == HIGH) {
    Serial.println(serial);
    Serial.println(logtijd);
  }



  if (millis() - Timer2 >= (logtijd) ) { // tijd wegschrijven naar SD kaart in msec en eventueel serial wanneer gekoezen bioj start loop
    if (serial == HIGH) {
      Serial.print(now.year(), DEC);
      Serial.print(F("/"));
      Serial.print(now.month(), DEC);
      Serial.print(F("/"));
      Serial.print(now.day(), DEC);
      Serial.print(F(" "));
      Serial.print(now.hour(), DEC);
      Serial.print(F(":"));
      Serial.print(now.minute(), DEC);
      Serial.print(F(" "));

    Serial.print(F(","));
    Serial.print(ds18b20A, 3);
    Serial.print(F(","));
    Serial.print(ds18b20B, 3);
    Serial.print(F(","));
    Serial.print(koppelA, 2);
    Serial.print(F(","));
    Serial.print(koppelB, 2);
    Serial.print(F(","));
    Serial.print(vinB, 3);
    Serial.print(F(","));
    Serial.print(vinA, 2);
    Serial.print(F(","));
    Serial.print(t, 2);
    Serial.print(F(","));
    Serial.print(h, 2);
    Serial.print(F(","));
    Serial.print(supplyVoltage, 2);
    Serial.print(F(","));
    Serial.print(Irms, 2);
    Serial.print(F(","));
    Serial.print(powerFActor, 2);
    Serial.print(F(","));
    Serial.print(realPower, 2);
    Serial.print(F(","));
    Serial.println(apparentPower, 2 );
    }

    // log datum tijd datum,tijd ,ch1,ch2,ch3,ch4,ch5,ch6,temperatuur,vocht,ac RMSvolt,RMSstroom,cosQ,realpower,apparentPower
    logfile.print(now.year(), DEC);
    logfile.print(F("-"));
    logfile.print(now.month(), DEC);
    logfile.print(F("-"));
    logfile.print(now.day(), DEC);
    logfile.print(F(" "));
    logfile.print(F(","));
    logfile.print(now.hour(), DEC);
    logfile.print(F(":"));
    logfile.print(now.minute(), DEC);
    logfile.print(F(":"));
    logfile.print(now.second(), DEC);
    //log alle data
    logfile.print(F(" "));
    logfile.print(F(","));
    logfile.print(ds18b20A, 3);
    logfile.print(F(","));
    logfile.print(ds18b20B, 3);
    logfile.print(F(","));
    logfile.print(koppelA, 2);
    logfile.print(F(","));
    logfile.print(koppelB, 2);
    logfile.print(F(","));
    logfile.print(vinB, 3);
    logfile.print(F(","));
    logfile.print(vinA, 2);
    logfile.print(F(","));
    logfile.print(t, 2);
    logfile.print(F(","));
    logfile.print(h, 2);
    logfile.print(F(","));
    logfile.print(supplyVoltage, 2);
    logfile.print(F(","));
    logfile.print(Irms, 2);
    logfile.print(F(","));
    logfile.print(powerFActor, 2);
    logfile.print(F(","));
    logfile.print(realPower, 2);
    logfile.print(F(","));
    logfile.println(apparentPower, 2 );

    logfile.flush();

    Timer2 = millis();
  }
}

Advertisement

Gebruikers-avatar
Berichten: 2655
Geregistreerd: 06 Aug 2016, 01:03

Re: DATA logger

Berichtdoor Koepel » 29 Nov 2020, 01:41

Het schrijven naar een (micro)SD geheugenkaartje duurt lang.
Het geoptimaliseerd lezen is 8 tot 12 kbyte per second, van schrijven weet ik het niet.

Zal ik alles wat mij opvalt hier gewoon neerzetten ? Kijk maar of er iets bij zit.

A.
Een I2C display is niet snel. Je kunt uittekenen wat je op het display wilt zetten.
Bijvoorbeeld "Hallo ±XXX.X V ±XX.XX A"
Voor het voltage hoef je alleen het formaat "±XXX.X" te maken met spaties op de lege plekken, bijvoorbeeld " 1.2". Die schrijf je op de juiste plek en klaar.
Dan hoef je het niet eerst leeg te maken.

B.
In plaats van "int serial" kun je dit doen:
Code: Alles selecteren
bool enableSerial = false;   // false or true

if( enableSerial)
{
  ...
}


C.
De OneWire library zet de interrupts even uit. Ik weet niet of dat een conflict oplevert voor de EmonLib.

D.
De 9600 baud is erg langzaam. Hoe lang is de regel die naar de seriële monitor wordt gestuurd ? Als dat meer dan 64 is, dan raakt de buffer vol. Dan wordt de sketch honderd keer langzamer.

E.
Dit is de default: SPI.setClockDivider( SPI_CLOCK_DIV4);
Dit is twee keer zo snel: SPI.setClockDivider( SPI_CLOCK_DIV2);
Dat kan wel bij een Ethernet shield, maar voor een SD kaartje wordt dat eigenlijk nooit gedaan. Je kunt het proberen.

F.
Staat ergens welk Arduino board je gebruikt ?

G.
De variabelen 'koppelA', 'koppelB', 'ds18b20A' en 'ds18b20B' geven niet in de naam aan dat het een temperatuur is. Dat zou toch wel fijn zijn, als dat duidelijk was.

H.
Wil je echt 100 keer per seconde de temperatuur opvragen ? De temperatuur van de DS18B20 wordt vaak eens per twee seconden opgevraagd. Maar als je dat ook echt doet, dan kan er "selfheating" ontstaan. Dan wordt hij warm omdat hij zo druk bezig is. Eens per 5 seconden is beter.

I.
De flush() is net zo langzaam als iedere keer het bestand openen en sluiten. Is het misschien netter om het bestand steeds opnieuw te openen en te sluiten ?

J.
Je kunt het wegschrijven naar het SD kaartje optimaliseren door de hele regel in een buffer te maken en die met één aanroep wegschrijven.

K.
Waarom roep je "lcd.backlight()" in de loop() steeds aan ? Dat gebruikt de I2C bus en kost tijd.

L.
Is het echt nodig om in de loop() steeds dht.begin() aan te roepen ?
De DHT sensors zijn langzaam. Die kun je ook eens per twee seconden of langzamer aanroepen.

Berichten: 88
Geregistreerd: 16 Jul 2015, 21:02

Re: DATA logger

Berichtdoor wim2584 » 29 Nov 2020, 17:37

Hallo Koepel,

Bedankt voor je opmerkingen, ga ik (in de toekomst) zeker wat mee doen, voor de temperatuur en vocht is natuurlijk 1x per 10 sec of meer, "meer dan voldoende", maar voor het DC volt en AC volt, zou het leuk geweest zijn sneller (een keer of 10 /sec) te samplen, nu bv. koelkast een poosje gevolgd ,"ouderwetse met een aan/uit compressor met hulpwikkeling, geen moderne met een frequentie gestuurde compressor", nu zie je dat bij inschakelen ongeveer 6 x nominale stroom word getrokken, bij hogere sampling rate zou dit duidelijker / leuker zijn, maar natuurlijk kan dat véél beter met een digitale storage scope.

maar heel erg bedankt voor je opmerkingen. zoal je ziet in mijn code , is programmeren niet mijn sterkste kant, maar als "oude man 61j :D " een jaar of 10 geleden ingezien dat het analoge tijdprek voorbij is en het nu véél gemakkelijker en beter digitaal gaat, helaas moet je dan wel programmeer skils bezitten!

de huidige code houd trouwens sample rate van 1 sec goed bij

gebruikte arduino is een kloon UNO

Terug naar Afgeronde projecten

Wie is er online?

Gebruikers in dit forum: Geen geregistreerde gebruikers en 1 gast