S7-300 über cp mit Arduino

Hallo, habe ein kleines problem,

ich möchte gerne den Arduino UNO über das Netzwerk mit meiner sps verbinden.

SPS: Siemens S7-317 mit Cp341 Bausteine AG_Send, AG_Recv.

Nun habe ich das Problem, das die Sps Daten sendet, die der Arduino auch auswertet aber zu spät

Beispiel die sende ein Byte: 0000_0001 nun vergehen ca 10 sekunden bis die LED am Arduino angeht ;(

Der empfang der daten geht Rasend schnell.

Sende die Analog in vom Arduino an die SPS via Hi und Lowbyte keine probleme läuft quasi “echtzeit”

vielleicht sendet die sps zuviel? Es sieht so aus, das die gesendete daten im “Stau” stecken …

hier mal der code: (da viel rumprobiert ist es durcheinander stellenweise led5 ist der ausgang led1-4 sind die eingänge, was aber erstmal nebensache ist. der blink ohne delay kommt übrigends super in der sps an)

#include <SPI.h>
#include <Ethernet.h>
const int ADC1 = A0;
byte input = 0;
byte output = 0;
int led1 = 2;
int led2 = 3;
int led3 = 4;
int led4 = 5;
int led5 = 6;


int ledState = 0;             // ledState used to set the LED
long previousMillis = 0;        // will store last time LED was updated
long interval = 1000;        




byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
byte ip[] = {192, 168, 0, 98};
EthernetServer server(50290);
// Sps <--- Arduino    1    2    3    4    5    6    7    8    9    10   11   12   13   14   15   16   17   18   19   20   21   22   23   24
byte byteArray[24] = {0x00,0x00,0x00,0x49,0x00,0x01,0x02,0x06,0x24,0x5a,0x44,0x20,0x42,0x75,0x73,0x2d,0x47,0x65,0x72,0x61,0x65,0x74,0x20,0x32};
String readBuffer;
// Sps ---> Arduino    1    2    3    4    5    6    7    8    9    10   11   12   13   14   15   16   17   18   19   20   21   22   23   24
byte byteArray2[24] = {0x01,0x00,0x00,0x49,0x00,0x01,0x02,0x06,0x24,0x5a,0x44,0x20,0x42,0x75,0x73,0x2d,0x47,0x65,0x72,0x61,0x65,0x74,0x20,0x32};


void setup()
{
  pinMode(led1, INPUT);
  pinMode(led2, INPUT);
  pinMode(led3, INPUT);
  pinMode(led4, INPUT);
  pinMode(led5, OUTPUT);
  
  Serial.begin(9600);
  Ethernet.begin(mac, ip);
  server.begin();
  delay(1000);
}

void loop()
{
 
  EthernetClient client = server.available();
  if (client) {
    while (client.connected()) {
      if (client.available()) {
       //char c = client.read();
       // readBuffer = readBuffer + c;
        //if (c == '\n') {    // warten auf new line
          byteArray2[0] = client.read();
      }
          server.write(byteArray, 24);
          //readBuffer = "";
          //delay(100);

  unsigned int ADC1 = analogRead(A0);
  byteArray[0] = highByte(ADC1);   
  byteArray[1] = lowByte(ADC1);
  unsigned int ADC2 = analogRead(A1);
  byteArray[2] = highByte(ADC2);   
  byteArray[3] = lowByte(ADC2);	
  unsigned int ADC3 = analogRead(A2);
  byteArray[4] = highByte(ADC3);   
  byteArray[5] = lowByte(ADC3);	
  unsigned int ADC4 = analogRead(A3);
  byteArray[6] = highByte(ADC4);   
  byteArray[7] = lowByte(ADC4);
  


  
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    if (ledState == 0)
      ledState = 1;
    else
      ledState = 0;}
      
      
 byteArray[8] = input;
  
  bitWrite(input,0,digitalRead(2));
  bitWrite(input,1,digitalRead(3)); 	
  bitWrite(input,2,digitalRead(4));
  bitWrite(input,3,digitalRead(5));
  bitWrite(input,4,ledState);
       Serial.println(ledState); 
       
 output = byteArray2[0];
  
  boolean x = bitRead(output,0);
  
  digitalWrite(led5,x);
  Serial.print("array: "); 
  Serial.println(byteArray2[0]);
  Serial.print("led5: ");
  Serial.println(bitRead(output,0)); 




    }    
  }
  client.stop();
}

hoffe ihr könnt mir helfen :slight_smile:

Erwartest Du, dass wir uns hier mit dem Siemens-Kauderwelsch auskennen? Was ist "AG_Send" bzw. "AG_Recv"? Sind das Bus-Anbindungen und falls ja, welche? Nach Deinem Code zu urteilen, dürfte es sich um eine Ethernet-Schnittstelle handeln. Ist das richtig? Wieso kann man das nicht gleich schreiben?

Beispiel die sende ein Byte: 0000_0001 nun vergehen ca 10 sekunden bis die LED am Arduino angeht ;(

Wundert mich nicht, Du schaltest die LED ja auch nicht beim Eingehen einer Nachricht, sondern zeitabhängig und das aber nur, wenn auch Traffic auf der Ethernet-Schnittstelle ist. Vielleicht solltest Du zuerst mal erklären, was Du überhaupt mit dem Sketch erreichen willst.

Ja, es handelt sich um Ethernet

Ag_send ist der Sendebaustein der definierte Anzahl an Bytes sendet in dem fall sendet er erstmal nur eins,

Der ag_recv ist das gleiche für den Empfang in dem fall hier werden die 24bytes des bytearrays übertragen.

Ziel ist es, das die SPS Eingänge sowohl digital und analog lesen kann und die Ausgänge ansteuern kann.

Vielleicht habt ihr ja eine idee

hi,

es gibt hier einige leute, die sich mit SPSen auskennen, aber es ist natürlich glückssache, wann die mal reinschneien, noch dazu in der urlaubszeit.

gruß stefan

Hallo, kenn mich schon mit SPS aus. Aber leider nicht mit Siemens, sondern vom Mitbewerber..

Aber ich würde mal versuchen das Programm in eine ordentliche Struktur zu bringen.. Dann kommst evtl. selber drauf, oder wir können leichter helfen.

Grüße, Jürgen

Also mir würde schon reichen, wenn ich das mit dem senden empfangen irgendwo Tutorial mäßig finde

Z.B mit schlusszeichen.

Erst empfangen, wenn Empfang von SPS ok, soll der arduino senden an der SPS

Mit welche Mitbewerber kennst du dich aus? Codesys?

Vielleicht kannst du mit ein kleines Beispiel geben, wie es mit deiner SPS ginge

Stehe echt auf dem Schlauch

Ag_send ist der Sendebaustein der definierte Anzahl an Bytes sendet in dem fall sendet er erstmal nur eins,

Und nach dem Senden unterbricht er die TCP-Verbindung, denn das ist genau das, worauf Du Dich in Deinem Sketch verlässt:

    while (client.connected()) {

Ich vermute, die 10 Sekunden sind die Wartezeit, nach der die SPS die Verbindung abbricht und Dein Sketch fährt erst dann mit der Verarbeitung fort.

Ich würde mal den Ratschlag von JuergenR beherzigen und den Sketch aufräumen (korrekte Formatierung wäre ein Anfang, die IDE macht das gratis und automatisch, wenn Du sie darum bittest).

Warum die Wartezeit von einer Sekunde in Deinem Sketch ist, hast Du uns immer noch nicht verraten.

Sehe ich das so (gekürzt - von oben kopiert) richtig:

void loop()
{
  ....
  EthernetClient client = server.available();
  if (client) {
  ....
  }
  client.stop();
}

Kaum ist die Bude in der Loop "auf", wird sie gleich wieder am Ende zu gemacht ?! Und das in der Hauptschleife ? Auch nicht grade wirklich hilfreich ....

Du solltest erst mal ein wenig struktuieren. Alles was einmalig initialisiert werden muss in void setup() { ... } packen. Dann mal schauen, was eigentlich wann genau passiert und danach passieren muss/soll. Das jeweils in eine eigene Funktion packen - das erhöht a) die Lesbarkeit und b) die Wartungs-/Erweiterungsfreundlichkeit ungemein !

EDITH: pylon war ne Kleinigkeit schneller und hat es vorweggenommen - lasse ich trotzdem mal so stehen.

Die Sekunde Delay habe ich drinne, da dies in vielen bespielen ist

Hab ihr evtl ein link wo man Lösungsansätze findet?

Die Formatierung mach die IDE aber nur beim schreiben oder auch nachträglich ?

Mit "Formatierung" war jetzt nicht gemeint, wie der Code in der Schreibweise dargestellt wird ! ... das bleibt jedem (oder dem jeweiligem Editor/User) selbst überlassen.

Sondern das zusammenfassen von Code, der sinngemäß am Stück z.B. bei einem bestimmten "Ereignis" wie: - ... neue Daten sind da - berechne, mache tue, ... oder - ... neue Daten sind zum Versand bereit, hau wech den Kram ... (, aber erst wenn) .... was man dann sozusagen "gekapselt" hat und dann nur noch die Funktion aufruft. Und wie schon gesagt: Alles was man einmalig initialisieren muss und global benötigt, gehört in die setup-Routine ! (Manche (!) C-Programmierer haben sich da bis heute leider einen äusserst w/liederlichen Stil angewöhnt und bis heute ungebrochen beibehalten !)

So was ist wie gesagt wesentlich besser zu "Händel'n" :. und dazu auch übersichtlicher.

Ok dann werde ich das noch einmal neu machen

Habt ihr da denn ein paar Anregungen ?

Stelle mit das so vor

Arduino: 4 Do, 4 Di, 4 Ai,

Ablauf: Verbinde mit SPS Empfänge von SPS 24 Bytes Die würde ich in ein bytearrays packen. Aus dem bytearray werden dann die Ausgänge gesetzt, zurückgesetzt.

Danach lese die analog und digital Input und packe die in ein bytearray Sende das bytearray(24byte) an die SPS

Danach fange wieder von vorne an.

Versuch's dann mal einfach ausgedrückt z.B. so:

funktion 'Verbinde mit SPS' - wenn verbunden, gleich wieder zurück - wenn nicht, mache Verbindungsversuch(e) bis klappt

funktion 'Empfange von SPS' - wenn Verbindung OK, dann ... sonst zurück und neuer Versuch - lese bis alle 24 Bytes da sind (dabei in ein bytearrays packen) - sonst zururück - wenn kplt. gelesen, Ausgänge setzen - danach Eingänge lesen und Werte in Array packen - ... und sende auch gleich an SPS ! - wenn fertig zurück

Setup: - alles einmal notwendige hier !

Loop: -> funktion 'Verbinde mit SPS' -> funktion 'Empfänge von SPS' ... und was sonst noch so ansteht.

das klingt ja garnicht so aufwendig.

allerdings komm ich mit der verbindung nicht klar

hast du da evtl die funktionen für mich? oder ein beispiel?

Finde leider nur beispiele über ein webserver, das brauch ich leider nicht

Packe doch mal

bitWrite(input,0,digitalRead(2));
  bitWrite(input,1,digitalRead(3)); 	
  bitWrite(input,2,digitalRead(4));
  bitWrite(input,3,digitalRead(5));
  bitWrite(input,4,ledState);
       Serial.println(ledState); 
       
 output = byteArray2[0];
  
  boolean x = bitRead(output,0);
  
  digitalWrite(led5,x);
  Serial.print("array: "); 
  Serial.println(byteArray2[0]);
  Serial.print("led5: ");
  Serial.println(bitRead(output,0));

hinter client.stop in die Hauptloop ich denke das dürfte so funktionieren.
Du schreibst die Daten an die Ausgänge nur wenn die Verbindung offen ist. Darein gehören aber nur die Zeilen für den Daten austausch.
Deine AnalogRead sachen pack doch auch einfach mal hinter den client Stop in die Hauptloop.
Dann dürfte es besser funktionieren.
Gruß
Der Dani

Hey kannst du mir vielleicht die S7-Programm mal schicken vielleicht kann man da was machen Gruß Der Dani

hat leider nichts gebracht :(

so habe jetzt noch etwas angepasst

#include <SPI.h>
#include <Ethernet.h>

int led1 = 2;
int led2 = 3;
int led3 = 4;
int led4 = 5;
int led5 = 6;

int ledState = 0;             // ledState used to set the LED
unsigned long previousMillis = 0;
long interval = 1000;        

// the media access control (ethernet hardware) address for the shield
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
// the IP address for the shield
byte ip[] = {192, 168, 0, 98};
// the port to listen on
EthernetServer server(50290);

// Sps <--- Arduino
byte byteArray[24];
// Sps ---> Arduino
byte byteArray2[24];


void setup()
{
  pinMode(led1, INPUT);
  pinMode(led2, INPUT);
  pinMode(led3, INPUT);
  pinMode(led4, INPUT);
  pinMode(led5, OUTPUT);
  
  Serial.begin(9600);
  
  // initialize the ethernet device
  Ethernet.begin(mac, ip);
  
  // start listening for clients
  server.begin();
}


void loop()
{
  unsigned int ADC1 = analogRead(A0);
  byteArray[0] = highByte(ADC1);   
  byteArray[1] = lowByte(ADC1);
  unsigned int ADC2 = analogRead(A1);
  byteArray[2] = highByte(ADC2);   
  byteArray[3] = lowByte(ADC2);	
  unsigned int ADC3 = analogRead(A2);
  byteArray[4] = highByte(ADC3);   
  byteArray[5] = lowByte(ADC3);	
  unsigned int ADC4 = analogRead(A3);
  byteArray[6] = highByte(ADC4);   
  byteArray[7] = lowByte(ADC4);
  
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis > interval) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    if (ledState == 0)
      ledState = 1;
    else
      ledState = 0;
  }
  
  bitWrite(byteArray[8],0,digitalRead(led1));
  bitWrite(byteArray[8],1,digitalRead(led2)); 	
  bitWrite(byteArray[8],2,digitalRead(led3));
  bitWrite(byteArray[8],3,digitalRead(led4));
  bitWrite(byteArray[8],4,ledState);
  Serial.println(ledState); 
  
  // if an incoming client connects, there will be bytes available to read
  EthernetClient client = server.available();
  
  if (client) {
    // read bytes from the incoming client
    byteArray2[0] = client.read();
    // write bytes to any clients connected to the server
    server.write(byteArray, 24);
    // übertragung erzwingen
    //client.flush();
    // 10ms delay damit daten sicher gesendet werden.
    delay(10);
    // wichtg! client verbindung beenden
    //client.stop();   
  }

  boolean x = bitRead(byteArray2[0],0);
  
  digitalWrite(led5,x);
  Serial.print("array: "); 
  Serial.println(byteArray2[0]);
  Serial.print("led5: ");
  Serial.println(bitRead(byteArray2[0],0)); 

}

allerdings ist in verbindung mit der SPS das immernoch mist.
Empfang vom Arduino läuft wie gehabt ohne Probleme
Senden an dem Arduino funktioniert zu langsam.

Mit dem Programm Hercules kann ich auf dem Arduino connecten und sende im Hexformat 00 = LED Aus; 01 = LED An.
sende ich aber ein CR dann flackert die led kurz

Sprich ich betätige in Hercules die Returntaste dann bekomme ich vom arduino die ganzen werte geschickt aber dabei flackert die led :-/
scheint also nicht am Arduinoprogramm zu liegen oder sehr ihr da noch fehler?

  if (client) {
    // read bytes from the incoming client
    byteArray2[0] = client.read();
    // write bytes to any clients connected to the server
    server.write(byteArray, 24);
    // übertragung erzwingen
    //client.flush();
    // 10ms delay damit daten sicher gesendet werden.
    delay(10);
    // wichtg! client verbindung beenden
    //client.stop();   
  }

Du liest nur ein Byte ein, danach überlässt Du die Verbindung ihrem Schicksal. Sauber wäre es, alle verfügbaren Daten einzulesen und dann die Verbindung (nach dem Versenden Deiner Daten) korrekt zu beenden (was bei Dir auskommentiert ist). Du solltest also im Minimum

while (client.available()) client.read();

einführen, damit die Puffer sauber geleert werden.

Aktuell wird von der SPS auch nur 1 Byte gesendet.

EDIT: habe nun den server.write mal rausgeschmisse, damit ich lediglig daten von der SPS zum Arduino senden kann.

Fazit: Arduino sendet nichts mehr an die sps, aber das problem besteht weiterhin bit in sps gesetzt, 10-15 sek später passiert etwas am arduino (LED geht an)

Bit auf 0 setzen 15-20 Sek später geht die led aus :(

Häng Dich mal mit einem PC an das Netzwerk (Hub oder Switch mit Monitoring-Port) und starte WireShark (oder ein vergleichbares Tool), damit Du siehst, was wann über das Netzwerk geht. Dann hast Du schnell herausgefunden, wer für die Verzögerung zuständig ist.

Edit: Was ist die Ausgabe auf der seriellen Schnittstelle? Bekommst Du dort auch für 10 Sekunden nach em Auslösen auf der SPS weiterhin den alten Wert gemeldet?