Go Down

Topic: Datenlogger zur Maschinendatenerfassung (Read 289 times) previous topic - next topic

Froederking

Mahlzeit :)

ich stelle mich erst einmal vor: Ich bin gelernter Elektroniker und Instandhalter für Werkzeugmaschinen. Ich bin meistens in der S7-Welt unterwegs und habe vorher wenig mit uC oder Arduinos zutun gehabt.

Für ein Projekt soll ich eine Test-Datenerfassung für die Laufzeiten von Maschinen erstellen.

Ich verwende einen ATMega mit dem Ethernet-Shield WIZ5100.

Nun zum Problem:

Im Grunde funktioniert mein Sketch ganz gut, auf die Eingänge des Arduinos sollen Ausgänge der Maschine gehen, die die jeweiligen Zustände signalisieren. Danach zählt der Arduino Sekundenweise die jeweilige Variable hoch und stellt sie via Ethernet bereit.

Dumm ist nur, das wenn mehr als ein Eingang HIGH ist sich der Arduino aufgrund meines Sketches verzählt, da ich mit delay-Befehlen arbeite.




Gibt es hier eine elegantere Lösung?



uwefed

millis() siehe Nachtwächtererklährung hier im Forum

DrDiettrich

Bitte zeige Deinen Sketch in Code Tags </>, damit er direkt lesbar ist. Es darf auch gerne eine kleinere Version sein, die den Fehler zeigt (z.B. ohne Ethernet aber Debug-Meldungen über Serial), aber compilieren sollte sie schon.

postmaster-ino

Hi

millis() wurde ja schon genannt - Du merkst Dir einfach, WANN der letzte Pegelwechsel bei dem Pin war.
Ist Das >=1000ms her, zählst Du 1 hoch und schiebst die gemerkte Zeit um 1000ms nach Hinten.

Das machst Du mit allen Pins - also jeweils!
Du brauchst also pro Pin den letzten Status und die letzte Zeit.
Wenn Sekundengenau reicht, sollte Das ungefähr so gehen:
Code: [Select]

pins[]={2,3,4,5}
elemente=sizeof(pins)/sizeof(pins[0]);  //die Anzahl der angegebenen Pins ermitteln
uint32_t lastchange[elemente];            //letzte Änderung des Pin
boolean laststatus[elemente];               //letzter Pegel
uint32_t ticks[elemente];                      //hochgezählte volle 'Sekunden'
const uint16_t wartezeit=1000;            //Wartezeit zum Hochzählen in ms für einen 'tick'

void setup(){
   for (byte x=0;x<elemente;x++){
      lastchange[x]=millis();
      laststatus[x]=digitalRead(pins[x]);
   }
}

void loop(){
   for (byte x=0;x<elemente;x++){
      if (digitalRead(pins[x])!=laststatus[x]){
         laststatus[x]=!laststatus[x];   //Status anpassen
         lastchange[x]=millis();           //und 'Uhrzeit' mithalten
      }
      if (laststatus[x]){                       //nur, wenn der Pin HIGH ist)
         if (millis()-lastchange[x]>=wartezeit){
            ticks[x]++;                          //und die Wartezeit vergangen ist
            lastchange[x]+=wartezeit;
         }
      }
   }
   //Hier die Daten 'alle Jubeljahr' verschicken
}


MfG
anscheinend ist Es nicht erwünscht, einen Foren-internen Link als 'Homepage' einzubinden, damit JEDER nur einen Klick von combie's Liste zum Thema State-Maschine entfernt ist.
... dann eben nicht ...

combie

#4
May 25, 2019, 03:07 pm Last Edit: May 25, 2019, 03:09 pm by combie
Quote
Dumm ist nur, das wenn mehr als ein Eingang HIGH ist sich der Arduino aufgrund meines Sketches verzählt, da ich mit delay-Befehlen arbeite.

Gibt es hier eine elegantere Lösung?
Ja, es geht viel eleganter!
Viel viel...

Aber hier eine quick'n dirty Lösung:
1. Alle vorhandenen delay(1000) ersatzlos streichen
2. Nur ein delay(1000) ganz an den Anfang von loop().



Der Pessimist sieht die Wolke vor der Sonne.
Der Optimist sieht die Sonne hinter der Wolke.

Mantra: Die Sonne scheint immer!

Doc_Arduino

Hallo,

bei den durchnummerierten Listen sticht eine Struktur ins Auge die man mittels angelegten Array durchlaufen lässt.

Bsp. für deine Eingänge einlesen.
Code: [Select]

const byte SIZE = 16;

struct Daten {
  byte pin;
  byte s;
  byte m;
  unsigned long h;
};

Daten mde[SIZE];


void setup()  {
  Serial.begin(9600);

  // Datenstruktur füllen und Eingänge konfigurieren
  byte pinStart = 22;
  for (byte i=0; i<SIZE; i++)
  {
    mde[i].pin = pinStart;        // Pinkonfig 22-37
    pinMode(mde[i].pin, INPUT);
    pinStart++;
  }
}

void loop() {

  read_Inputs();

}


void read_Inputs ()
{
  for (byte i=0; i<SIZE; i++)
  {
    if (digitalRead(mde[i].pin)) {
      mde[i].s++;

      if (mde[i].s > 59) {
        mde[i].s = 0;
        mde[i].m++;
      }
      
      if (mde[i].m > 59) {
        mde[i].m = 0;
        mde[i].h++;
      }
    }
  }
}


Das gleiche machst du mit deiner Ethernet Geschichte und rufst die Funktionen mittels millis aller x ms auf. Fertig.


Theseus erklärt millis()
http://forum.arduino.cc/index.php?topic=400102.msg2752141#msg2752141

GuntherB - BlinkwithoutDelay - Die Nachtwächtererklärung
http://forum.arduino.cc/index.php?topic=423688.0
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

combie

#6
May 25, 2019, 04:14 pm Last Edit: May 26, 2019, 09:04 pm by combie
Quote
bei den durchnummerierten Listen sticht eine Struktur ins Auge
So ist es!

(ich hasse Codeduplikate und ALLE durchnummerierten Dinger)



Da ich gerade kein Ethernet zum testen aktiv habe, kann man ein p auf der SeriellenKonsole eingeben um sich die ganzen MDE Dinge im Monitor anzeigen zu lassen

Alle Duplikate entfernt.
Alle überflüssigen Delay entfernt.
Alle Durchnummeriereungen entfernt
Ansonsten, recht unverändert
Code: [Select]
//#include <SD.h>
#include <SPI.h>
#include <Ethernet.h>
#include <Streaming.h> // die Lib findest du schon ... ;-)



class Logport : public Printable
{
  private:
   const byte pin;
   unsigned long laufzeit;

  public:
   Logport(const byte pin):pin(pin),laufzeit(0){}

   void begin()
   {
     pinMode(pin,OUTPUT);
   }

   void log()
   {
     laufzeit += digitalRead(pin);
   }

   size_t printTo(Print &p) const
   {
      size_t len = 0;
      len += p.print(" Laufzeit ist ");
      len += p.print(laufzeit / (60 * 60));
      len += p.print("h ");
      len += p.print(laufzeit / 60 % 60);
      len += p.print("m ");
      len += p.print(laufzeit % 60);
      len += p.print("s");
      return len;
  }
};


Logport logports[] {21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,};

byte mac[] = {
  0xDE, 0xAD, 0x0E, 0xEF, 0xFE, 0xFF
};
IPAddress ip(192, 168, 0, 177);
EthernetServer server(80);




void setup()
{
 
  Ethernet.init(10);

  for(Logport &port:logports) port.begin();



  Serial.begin(9600);
  while (!Serial) {
    ;
  }
  Serial.println("MDE Webserver");
  Ethernet.begin(mac, ip);


  if (Ethernet.hardwareStatus() == EthernetNoHardware) {
    Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
    while (true) {
      delay(1); // do nothing, no point running without Ethernet hardware
    }
  }
  if (Ethernet.linkStatus() == LinkOFF) {
    Serial.println("Ethernet cable is not connected.");
  }

  
  server.begin();

  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
}

void serialEvent()
{
  int in = Serial.read();
  int portnum = 1;
  if(in == 'p')
  {
    for(Logport &port:logports) Serial << "MDE" << portnum++ << port << endl;
    Serial << endl;
  }
}


void loop()
{
  static unsigned long timestamp = 0;
  if(millis() - timestamp >= 1000)
  {
    timestamp += 1000;
    for(Logport &port:logports) port.log();
  }
  

  
  


      
  EthernetClient client = server.available();
  if (client) {
    Serial.println("new client");
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank) {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the response
          client.println("Refresh: 5");  // refresh the page automatically every 5 sec
          client.println();
          client.println("<!DOCTYPE HTML>");
          client.println("<html>");

          int portnum = 1;
          for(Logport &port:logports) client << "MDE" << portnum++ << port << "<br /> <br />" << endl;
    
          client << "</html>" << endl;

        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        } else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
    Serial.println("client disconnected");
  }
}

Der Pessimist sieht die Wolke vor der Sonne.
Der Optimist sieht die Sonne hinter der Wolke.

Mantra: Die Sonne scheint immer!

volvodani

Wenn du in der S7 Welt zuhause bis (sowie meiner einer) dann solltest du (wenn die original Anlage auch ne S7 hat). Mal hier auf die Seite gehen >>Klick<< . Danmit kanst du diekt an deine S7 mit PN gehen und die Daten direkt abgreifen. Solltest du eine S7-1200 V4 und größer haben dann muss PUT/GET von extern aktiviert werden im Reiter Security bei den CPU Eigenschaften. Das gleiche gibt es auch bei den 1500er ich kann aber nicht sagen ab welcher Firmware PUT/GET von Haus aus deaktiviert ist.
Ich habe es erfolgreich mit ner S7-1211C und nem Arduino MEGA mit EthernetKarte gemacht und mit einem ESP8266 via WLAN

Gruß
DerDani
"Komm wir essen Opa!" - Satzzeichen retten Leben!

Scherheinz

 Sofern die CPUs nicht nur Profibus und MPI Anschlüsse haben, wer weiß wie alt die Anlagen sind.  ;)
Ich benutze aber auch Settimino um Daten von ein paar CPUs aus einem großen Verbundnetz zu ziehen. Das funktioniert wunderbar und bringt auch niemand in Schwierigkeiten solange man nur lesend auf die Daten zugreift.

Gruß
Hier könnte ihre Werbung stehen

Froederking

#9
May 26, 2019, 07:31 pm Last Edit: May 26, 2019, 07:42 pm by Froederking
Danke für die vielen Antworten  :)

Ich probiere die vielen Lösungen nacheinander mal aus und schau mir das settimo mal an.

Geb dann Bescheid für welche dieser Lösungen ich mich entschieden habe :)

Wenn ich die Lösung von Combie ausprobiere kommt diese Fehlermeldung:


Arduino: 1.8.9 (Windows Store 1.8.21.0) (Windows 10), Board: "Arduino/Genuino Mega or Mega 2560, ATmega2560 (Mega 2560)"

WARNUNG: Kategorie 'Language' in der Bibliothek ArduinoStreaming ist ungültig und wird auf 'Uncategorized' festgelegt
sketch_may26a:39:72: error: field 'logports' has incomplete type 'Logport
  • '


 Logport logports[] {21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,};

                                                                        ^

C:\Users\lfroe\Documents\Arduino\sketch_may26a\sketch_may26a.ino:6:7: note: definition of 'class Logport' is not complete until the closing brace

 class Logport : public Printable

       ^

sketch_may26a:44:14: error: expected identifier before numeric constant

 IPAddress ip(192, 168, 0, 177);

              ^

sketch_may26a:44:14: error: expected ',' or '...' before numeric constant

sketch_may26a:45:23: error: expected identifier before numeric constant

 EthernetServer server(80);

                       ^

sketch_may26a:45:23: error: expected ',' or '...' before numeric constant

sketch_may26a:154:1: error: expected '}' at end of input

 }

 ^

sketch_may26a:43:1: error: too many initializers for 'byte
  • {aka unsigned char
  • }'


 };

 ^

C:\Users\lfroe\Documents\Arduino\sketch_may26a\sketch_may26a.ino: In member function 'void Logport::setup()':

sketch_may26a:64:25: error: invalid use of non-static member function

   Ethernet.begin(mac, ip);

                         ^

sketch_may26a:78:3: error: '((Logport*)this)->Logport::server' does not have class type

   server.begin();

   ^

C:\Users\lfroe\Documents\Arduino\sketch_may26a\sketch_may26a.ino: In member function 'void Logport::loop()':

sketch_may26a:111:27: error: '((Logport*)this)->Logport::server' does not have class type

   EthernetClient client = server.available();

                           ^

C:\Users\lfroe\Documents\Arduino\sketch_may26a\sketch_may26a.ino: At global scope:

sketch_may26a:154:1: error: expected unqualified-id at end of input

 }

 ^

exit status 1
field 'logports' has incomplete type 'Logport
  • '


Dieser Bericht wäre detaillierter, wenn die Option
"Ausführliche Ausgabe während der Kompilierung"
in Datei -> Voreinstellungen aktiviert wäre.

Fehlt da nicht die gescheifte Klammer?

Doc_Arduino

#10
May 26, 2019, 08:54 pm Last Edit: May 26, 2019, 08:55 pm by Doc_Arduino
Hallo,

eine Klammer am Ende der Klasse Logport ... vor der Abschließenden  };
Danach bekomme ich nur noch 2 Warnungen der Ethernet Lib.
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

combie

Hallo,

eine Klammer am Ende der Klasse Logport ... vor der Abschließenden  };
Danach bekomme ich nur noch 2 Warnungen der Ethernet Lib.
1. Ist korrigiert (ka, wie der Fehler entstanden ist)
2. Die Lib ist noch nicht für  C++17 vorbereitet
Der Pessimist sieht die Wolke vor der Sonne.
Der Optimist sieht die Sonne hinter der Wolke.

Mantra: Die Sonne scheint immer!

Doc_Arduino

Hallo,

ist mir auch schon einmal passiert, einmal zu viel copy & paste und schon   :)
Bei mir macht die Seite hier auch unnötig und selbstständig zusätzliche Leerzeilen rein. Nicht im Code, im Text.

Wegen den Warnungen. Liegt das daran das jede neuere Compilerversion den Code strenger prüfen kann?
Also den Syntax besser lesen kann?
Tschau
Doc Arduino '\0'

Messschieber auslesen: http://forum.arduino.cc/index.php?topic=273445
EA-DOGM Display - Demos: http://forum.arduino.cc/index.php?topic=378279

combie

#13
May 27, 2019, 01:28 am Last Edit: May 27, 2019, 01:33 am by combie
switch()  wurde verändert.
Im Zuge dessen wurden die Meldungen verschärft.
Der Pessimist sieht die Wolke vor der Sonne.
Der Optimist sieht die Sonne hinter der Wolke.

Mantra: Die Sonne scheint immer!

Froederking

Abend  :)

Nochmals ein Dankeschön für die Mühe die ihr euch hier alle macht, hab noch große Schwierigkeiten mich in der Programmiersprache zurecht zu finden, deshalb dauert es immer ein bissel ehe ich antworte;). Ich teste gerade eine Mischung aus der Lösung von Doc_arduino und postmaster-ino. Muss ich nun den ethernet-Teil in den void loop() schreiben in etwa so:

            client.print(mde.s);
            client.print("h ");
            client.print(mde.m);
            client.print("m ");
            client.print(mde.h);
            client.print("s ");
           
            client.println("<br />");
            client.println("<br />");


oder muss ich hierfür einen "extra"-void machen, z.B. void ethernet.

Eine Frage noch an combie, dein sketch ist mittlerweile hochladbar, jedoch bekomme ich nichts angezeigt, wenn ich im Browser die ip eintippe, es lädt lediglich endlos. Wenn ich den Programmteil richtig intepretiere sollten da doch die einzelnen Logports stehen oder?

Und zu meiner letzten Frage, die geht an Scherheinz und/oder volvodani:

Ist es möglich zwei ethernet-shields auf einem arduino zu betreiben? Wir haben leider kein sehr stabiles WLAN im Haus und wenn die Schweißerei anfängt Plasma zu brennen ist es mitn Empfang eh vorbei ;)

Go Up