TIA Modbus Kommunikation (SPS zu MPA) -> Fehlerbehebung von Modbus_Master

HT-T

Level-2
Beiträge
109
Reaktionspunkte
3
Zuviel Werbung?
-> Hier kostenlos registrieren
Liebe SPS-Forum Gemeinde,
es ist wieder so weit. Meine Verzweiflung ist hoch genug hier erneut einen Beitrag zu verfassen in der Hoffnung das mir wie bisher immer geholfen wird.

Nun zu meinem eigentlichen Anliegen...
Ich möchte mit folgenden Komponenten:
CPU 1214C AC/DC/Rly - 6ES7 214-1BG40-0XB0
CM 1241 (RS422/485) - 6ES7 241-1CH32-0XB0

Eine Modbusverbindung zwischen der SPS und einer Dungs MPA (siehe Bedienungsanleitung im Anhang) herstellen. Als erstes würde ich gerne die Wärmeanforderung mit Hilfe der SPS schreiben und von 0 auf 1 setzen, da dies ein einfach zu setzendes Bit sein sollte und ich auf dem Gerät zudem eine LED habe welche mir das erfolgreiche Setzen somit rückmelden würde.

Von Seitens der MPA habe ich alle weiteren Vorkehrung wie in dem Manual beschrieben umgesetzt. Das heißt die Dipp-Schalter entsprechend gesetzt, den entsprechenden Parameter auf einen Wunsch Port gesetzt (100). Trotzdem soll es irgendwie nicht klappen.

Die Bausteine Modbus_Comm und Modbus_Master habe ich auch schon in meinen OB1 eingefügt und nach bestem WIssen und Gewissen parametriert.
Der Modbus_Comm wird auch erfolgreich geladen, jedoch spuckt mir der Modbus_Master immer wieder folgende Fehlermeldungen aus. (siehe Anhang weiter unten).

Ich habe leider keinerlei Erfahrung im Bereich von Modbus und der generellen Master-Slave Bausteine.
Nach meinem Verständnis sollte doch das Ausgangsbyte AB0 mit Bit 0 die Adresse 0 mit der Länge 1 besitzen oder denke ich hier falsch.

Jedenfalls würde ich mich über Unterstützung freuen, solltet ihr noch weitere Fragen haben lasst es mich wissen.
Bis dahin euer HT-T

1711464982282.png1711465254019.png
 

Anhänge

  • 300966_MPA_Betriebsanleitung.pdf
    7,9 MB · Aufrufe: 10
  • 1.PNG
    1.PNG
    105,6 KB · Aufrufe: 36
  • 2.PNG
    2.PNG
    111,4 KB · Aufrufe: 35
Hmm... auf die schnelle sehe ich nichts auffälliges.
Nehme an dass der MB_COMM_LOAD sauber gelaufen ist und Baudrate und sonstiges stimmt.
Laut Beschaltung des MB_MASTER versuchst du Halteregister 1 (Adresse 0) zu schreiben. Scheint auch stimmig.

Mit dem Fehler 16#8281 kann ich auch nichts anfangen. Frage ist ob man dem 16#8189 glauben kann.
Hast du schon mal einen einfachen Lese-Zugriff versucht? Also z.B. InputRegister1 (Mode=1, Addr = 30001, Len= 1) .
Wäre interessant ob ein Lesezugriff tut.

Hast du einen USB/RS485-Umsetzer rumliegen?
Dann könntest du eventuell den Schreibzugriff auf Holding-Reg1 mit nem PC testen.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich habe leider keinerlei Erfahrung im Bereich von Modbus und der generellen Master-Slave Bausteine.
Nach meinem Verständnis sollte doch das Ausgangsbyte AB0 mit Bit 0 die Adresse 0 mit der Länge 1 besitzen oder denke ich hier falsch.
Hier kann ich dir nicht ganz folgen.

Meinst du AB0 auf der SPS-Seite, also Ausgangsbyte 0 der SPS?
Hier würde ich nicht sehen wo das AB0 in deinem Beispiel/Screenshots vorkommt.

Oder meinst du mit AB0 etwas auf Modbus-Seite?
 
Kommunikationstechnisch fällt mir auch nichts auf. Sehr verdächtig erscheint mir allerdings die Belegung am DATA_PTR des Modbus_Master. Register 3 ist ja bestimmt nicht das, was eigentlich gesendet werden soll? Das erklärt allerdings nicht die beiden Fehlermeldungen.

Warum konntet ihr nicht die DP-Schnittstelle verwenden?
 
.. den entsprechenden Parameter auf einen Wunsch Port gesetzt (100).
Damit ist die Modbus-Adresse gemeint? Diese ist auch eingestellt worden, laut Anleitung über eine "VisionBox"? Und das Gerät wurde anschließend, ebenfalls nach Anleitung, neu gestartet?

Dann gibt es auch noch die Einstellungen in den Eigenschaften des CM1241 unter RS485-Schnittstelle.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Moin,
vielleicht hilft das ja weiter:

Ich hatte mal was mit einer Mod-Bus-Verbindung von Endress&Hauser zu tun. Hier war leider die Bedienungsanleitung sehr dürftig und der Support und ich hatten immer wieder aneinander vorbei geredet...

2. Sachen, an die ich mich noch erinnern kann:
- da ich nicht nur ein Byte schicke / empfange habe ich ein String zusammengebastelt. Da dürfen natürlich nicht die ersten beiden Byte (Strinlänge/Textlänge) übertragen werden
- zusätzlich musste noch am Ende des String eine Checksumme mitgeschickt werden, sonst wurde alles am E&H Teilnehmer komplett ignoriert

LG Dirk
 
Hmm... auf die schnelle sehe ich nichts auffälliges.
Nehme an dass der MB_COMM_LOAD sauber gelaufen ist und Baudrate und sonstiges stimmt.
Laut Beschaltung des MB_MASTER versuchst du Halteregister 1 (Adresse 0) zu schreiben. Scheint auch stimmig.

Mit dem Fehler 16#8281 kann ich auch nichts anfangen. Frage ist ob man dem 16#8189 glauben kann.
Hast du schon mal einen einfachen Lese-Zugriff versucht? Also z.B. InputRegister1 (Mode=1, Addr = 30001, Len= 1) .
Wäre interessant ob ein Lesezugriff tut.

Hast du einen USB/RS485-Umsetzer rumliegen?
Dann könntest du eventuell den Schreibzugriff auf Holding-Reg1 mit nem PC testen.
Hallo Ronin,
danke für die schnelle Antwort!
Ich werde das mit dem Lesezugriff noch probieren, mittlerweile habe ich auch die Eigenschaften des CM-Moduls gecheckt und Änderungen vorgenommen ich bin nur noch nicht zum erneuten Testen gekommen.
Der Vorschlag mit dem USB/RS485 Umsetzer ist auch eine gute Idee, beim Beschaffen der Komponenten habe ich das jedoch leider nicht berücksichtigt und lediglich ein klassisches Kabel bestellt. 😒
 
Hier kann ich dir nicht ganz folgen.

Meinst du AB0 auf der SPS-Seite, also Ausgangsbyte 0 der SPS?
Hier würde ich nicht sehen wo das AB0 in deinem Beispiel/Screenshots vorkommt.

Oder meinst du mit AB0 etwas auf Modbus-Seite?
Ich habe mich hier etwas ungeschickt ausgedrückt, gemeint war der Ausgangsbyte-Register in welchem meine "Wärmeanforderung" enthalten ist. Hier habe ich auf Seite.80 der Bedienungsanleitung Bezug genommen, wobei das nicht richtig ist wie mir mittlerweile aufgefallen ist, da das für Profibus gilt. Seite.87 ist hier das richtige 16Bit Register auf das ich versuchen möchte zu schreiben.1712042492427.png
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Kommunikationstechnisch fällt mir auch nichts auf. Sehr verdächtig erscheint mir allerdings die Belegung am DATA_PTR des Modbus_Master. Register 3 ist ja bestimmt nicht das, was eigentlich gesendet werden soll? Das erklärt allerdings nicht die beiden Fehlermeldungen.

Warum konntet ihr nicht die DP-Schnittstelle verwenden?
Hallo Onkel Dagobert,
auch dir vielen Dank für die Mühe und zeitige Antwort!
Danke im speziellen für den Hinweis mit der DATA_PTR Adressierung, hier hast du natürlich recht dieser war nicht richtig ausgewählt.
Ich habe mittlerweile einen globalen PLC-Datentyp erstellt mit Datentyp WORD und dem Wert - 16#FF00. Dieser soll, so wie ich mittlerweile herausgefunden habe dem richtigen Format entsprechen um eine Bitadresse auf TRUE zu setzen. Ich konnte es bisher noch nicht testen, sobald ich das getan habe werde ich euch jedoch auf dem Laufenden halten. :)

Wenn ich deine Frage richtig verstehe möchtest du wissen weshalb wir und für Modbus, und nicht für Profibus entschieden haben? Wir möchten die Steuerung in einen bestehenden Prüfstand integrieren weshalb wir uns aufgrund der dort verbauten Hardware Kombination für den Modbus entschieden haben.

Ich habe jetzt schon von mehreren Stellen gehört das die Profibus Umsetzung wesentlich einfacher als die Modbus Anwendung sei, jedoch lernt und wächst man ja mit seinen Aufgaben. ;)
 
Zuletzt bearbeitet:
Damit ist die Modbus-Adresse gemeint? Diese ist auch eingestellt worden, laut Anleitung über eine "VisionBox"? Und das Gerät wurde anschließend, ebenfalls nach Anleitung, neu gestartet?

Dann gibt es auch noch die Einstellungen in den Eigenschaften des CM1241 unter RS485-Schnittstelle.
Ja genau damit ist die Modbus-Adresse gemeint, ich bin hier genau nach Anleitung vorgegangen weshalb ich diese Fehlerquelle eigentlich ausschließen kann.

Danke für den Hinweis, hier habe ich diese Einstellungen auch wie folgt bisher angepasst:
Laut Bedienungsanleitung hat die MPA per Default 19.2k Baudrate und eine Gerade Parität. Bei der Festlegung des "Stoppbits" bin ich leider etwas ratlos da dieser Parameter unerwähnt bleibt... hier steht die Auswahl "1" oder "2" zur Option.

Zur "Vorbelegung der Empfangsleitung" habe ich Versuchsweiße nun einmal die Vorspannung ausgewählt, wobei ich mir hier jedoch auch nicht sicher bin.

Beim Protokoll habe ich unverändert den "Freeport" belassen, alternativ wäre hier noch "3964(R)" auszuwählen wobei mir auch hier keine weiteren Informationen vorliegen.

1712043111022.png
 
Moin,
vielleicht hilft das ja weiter:

Ich hatte mal was mit einer Mod-Bus-Verbindung von Endress&Hauser zu tun. Hier war leider die Bedienungsanleitung sehr dürftig und der Support und ich hatten immer wieder aneinander vorbei geredet...

2. Sachen, an die ich mich noch erinnern kann:
- da ich nicht nur ein Byte schicke / empfange habe ich ein String zusammengebastelt. Da dürfen natürlich nicht die ersten beiden Byte (Strinlänge/Textlänge) übertragen werden
- zusätzlich musste noch am Ende des String eine Checksumme mitgeschickt werden, sonst wurde alles am E&H Teilnehmer komplett ignoriert

LG Dirk
Hallo Dirk,
auch dir erstmal ein Dankeschön für deinen Beitrag!

Ich verstehe nicht ganz wie du mit einer Zeichenkette, also einem String, ein Byte schreiben konntest. Aus meinen rudimentären Informatik Kenntnissen habe ich verstanden das es wichtig ist den richtigen Datentyp ( je nach Bitumfang ) auszuwählen, in meinem Fall dürfte das ein WORD (16BIT) sein.

Hast du das Ganze denn auch im TIA Portal mit genannten Bausteinen umgesetzt?
Von der Checksumme habe ich bereits gehört, jedoch sollte das aus meinem Verständnis heraus der Baustein selbst übernehmen, da ich hier keinerlei Eingabeaufforderung vorfinde.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Es gibt Neuigkeiten...
Ich habe gerade nochmal getestet und habe jetzt folgendes Fehlerbild:

Immerhin habe ich nun anstatt zwei Fehlern nur noch einen :LOL:

Kann jemand an der, für mich kryptischen, Fehlerbeschreibung etwas konkretes ableiten?
Ich habe Google bereits bemüht, bin aber auf keinerlei hilfreiche Beiträge gestoßen...
1712135240390.png
1712135265112.png1712135399219.png
 
Hallo,

Eingang DATA_PTR ist falsch belegt. Nach Deinem Screenshot sollte das "GlobalerSpeicher".dataPtr.data sein.

16#FF00 zu senden könnte auch noch nicht ganz richtig sein. Damit wird ja gleich alles gesetzt/gestartet. Ist das wirklich so vorgesehen bei dem Gerät?

Gruß
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

Eingang DATA_PTR ist falsch belegt. Nach Deinem Screenshot sollte das "GlobalerSpeicher".dataPtr.data sein.

16#FF00 zu senden könnte auch noch nicht ganz richtig sein. Damit wird ja gleich alles gesetzt/gestartet. Ist das wirklich so vorgesehen bei dem Gerät?

Gruß
Hallo Thruser,
da hast du natürlich recht... Flüchtigkeitsfehler von mir, ich habe nun direkt auf das erste Word im Array also data[0] adressiert.

Den Hinweis zu "16#FF00" habe ich aus dem Informationssystem entnommen - Modbus-Master:
Ich möchte im Ausgangsbyte 0 Registeradresse 0 ansprechen und auf TRUE setzen...
1712143928676.png

Jetzt habe ich wieder Fehlermeldung:
16#7001 und 16#8281...
1712144122885.png

Ich verstehe nicht wie der Parameter PORT am Modbus_Master überprüft werden soll, wenn dieser Baustein nicht einen solchen zuweisbaren Parameter besitzt....

1712145026144.png
 
Zuletzt bearbeitet:
OK, habe übersehen, daß Du dort 1 Bit/Coil (FC 5) schreiben willst. Da stellt sich die Frage, ob man die Bits darüber ansprechen kann. Das ist mir aus der Anleitung so nicht ersichtlich.

Zu dem anderen Fehler kann ich nichts sagen.

Gruß
 
Hallo Dirk,
auch dir erstmal ein Dankeschön für deinen Beitrag!

Ich verstehe nicht ganz wie du mit einer Zeichenkette, also einem String, ein Byte schreiben konntest. Aus meinen rudimentären Informatik Kenntnissen habe ich verstanden das es wichtig ist den richtigen Datentyp ( je nach Bitumfang ) auszuwählen, in meinem Fall dürfte das ein WORD (16BIT) sein.

Hast du das Ganze denn auch im TIA Portal mit genannten Bausteinen umgesetzt?
Von der Checksumme habe ich bereits gehört, jedoch sollte das aus meinem Verständnis heraus der Baustein selbst übernehmen, da ich hier keinerlei Eingabeaufforderung vorfinde.

Moin,
ich habe heute morgen mir das ganze mal genauer angeschaut, was ich da mal zusammengeschrieben hatte: Meisten habe ich mir angewöhnt immer ein paar Kommentare ran zu schreiben...

Zum Code: Die SPS sendet als String ein paar Daten - wie z.B. Adresse vom Teilnehmer, Funktionscode (Ist Vorgabe von E&H) und ich bekomme dann eine Antwort. Diesen String zerlege ich um die einzelnen Daten daraus zu bekommen (Temperatur, Durchfluss usw.).


Code:
// *********************************************************************************************************************************
// *** EndressHauser LAN
// *********************************************************************************************************************************


// *********************************************************************************************************************************
// *** UDT für Datenausgabe
// *********************************************************************************************************************************

TYPE UDT_EuH
    STRUCT
        SWG70:                      STRUCT
            Temperatur:                 REAL;               // Temperatur Elektronik in °C
            SignalPegel:                REAL;               // Singalpegel in dB
                                    END_STRUCT;
        
        Sensor:                     STRUCT
            Strom_Analog:               REAL;               // in mA
            Durchfluss:                 REAL;               // in L/Min
            Menge_Netto:                REAL;               // in m³ (vorwärts - rückwärts)
            Menge_vorwaerts:            REAL;               // in m³
            Menge_rueckwaerts:          REAL;               // in m³
                                    END_STRUCT;
    END_STRUCT
END_TYPE





// *********************************************************************************************************************************
// *** FB E&H
// *********************************************************************************************************************************

FUNCTION_BLOCK EndressHauser
 TITLE = 'Signalaustausch E&H'
 AUTHOR: Gollasch
 VERSION: '1.0'

VAR_INPUT
    PEW_Start:                  INT;                        // erste P-Adresse
    PAW_Start:                  INT;                        // erste P-Adresse
END_VAR


VAR_IN_OUT
END_VAR


VAR_OUTPUT
    DatenAusgabe:                UDT_EuH;
END_VAR


VAR
    InstandzDB_P_RCV:           P_RCV;
    InstandzDB_P_SEND:          P_SEND;

    SendeDaten01:               BYTE;   // Adresse E&H
    SendeDaten02:               BYTE;   // Funktionscode
    SendeDaten03:               WORD;   // Startadresse
    SendeDaten04:               WORD;   // DatenLänge
    SendeDaten05:               WORD;   // Checksumme
    SendeDaten06:               INT;    // Länge Sendedaten
    
    vBlinker:                   Blinker;
    
    Daten:                      ARRAY[0..300] OF BYTE;
END_VAR


VAR_TEMP
    tPointer_Struct:        STRUCT
        tID:                    BYTE;                               // ID für ANY (10 hex = S7-Format)
        tDataTyp:               BYTE;                               // ID für ANY (02 hex = es wird mit Bytes gearbeitet)
        tLaenge:                INT;                                // Anzahl Daten
        tDB_Nummer:             INT;                                // DB der im ANY Pointer benutzt wird
        tByte_Bit:              DWORD;                              // Byte und Bit
                            END_STRUCT;                             //
    tPointer AT tPointer_Struct: ANY;                               // ANY-Pointer zur Struktur

    tID:                    BYTE;                                   // ID für ANY (10 hex = S7-Format)
    tDataTyp:               BYTE;                                   // ID für ANY (02 hex = es wird mit Bytes gearbeitet)
    tLaenge:                INT;                                    // Anzahl Daten
    tDB_Nummer:             INT;                                    // DB der im ANY Pointer benutzt wird
    tByte_Bit:              DWORD;                                  // Byte und Bit
    tStartAdresse:          INT;                                    // tByte_Bit ind Startadresse umgerechnet

    tMoveReal:              REAL;
    tMoveWord AT tMoveReal: DWORD;

    tSchleife:              INT;
    tNeuWert:               BOOL;

    tSendetakt:             BOOL;
    tEmpfang:               BOOL;

    Dummy_Bool:             BOOL;
    Dummy_INT:              INT;
    Dummy_Word:             WORD;
    Dummy_DWord:            DWORD;
    Dummy_Real:             REAL;
    Dummy_Time:             TIME;
END_VAR


LABEL
END_LABEL






BEGIN


// Takt zum senden
    vBlinker(iZeit_EIN:= t#1s
            ,iZeit_AUS:= t#5s);
        tSendetakt:= vBlinker.oAusgang;
        Dummy_Time:= vBlinker.oRestZeit_EIN;
        Dummy_Time:= vBlinker.oRestZeit_AUS;





// Daten an E&H senden
    // SendeCode an E&H
    SendeDaten01:= B#16#01;     // Adresse vom WirelessHart-Fieldgate SWG70
    SendeDaten02:= B#16#04;     // Funktionscode
    SendeDaten03:= W#16#0000;   // Startadresse
    SendeDaten04:= W#16#0030;   // DatenLänge (28 Byte)
    SendeDaten05:= W#16#F01E; //F1C3;   // Checksumme
    SendeDaten06:= 8;           // Länge Sendedaten
 
 
    // Pointer für DB und Startadresse
    tPointer:= SendeDaten01;                                               // DB auslesen
        tID:=        tPointer_Struct.tID;
        tDataTyp:=   tPointer_Struct.tDataTyp;
        tLaenge:=    tPointer_Struct.tLaenge;
        tDB_Nummer:= tPointer_Struct.tDB_Nummer;
        tByte_Bit:=  tPointer_Struct.tByte_Bit;
        tStartAdresse:= DWORD_TO_INT(SHR(IN := tByte_Bit AND 16#00ffffff, N := 3));

        tLaenge:= SendeDaten06;


    // nach E&H senden
    InstandzDB_P_SEND(REQ:= tSendetakt
                     ,R:= false
                     ,LADDR:= PAW_Start
                     ,DB_NO:= tDB_Nummer
                     ,DBB_NO:= tStartAdresse
                     ,LEN:= tLaenge);
        Dummy_Bool:= InstandzDB_P_SEND.DONE;
        Dummy_Bool:= InstandzDB_P_SEND.ERROR;
        Dummy_Word:= InstandzDB_P_SEND.STATUS;
 







// Daten von E&H lesen
    // BD und Startadresse suchen
    tPointer:= Daten;                                             // DB auslesen
        tID:=        tPointer_Struct.tID;
        tDataTyp:=   tPointer_Struct.tDataTyp;
        tLaenge:=    tPointer_Struct.tLaenge;
        tDB_Nummer:= tPointer_Struct.tDB_Nummer;
        tByte_Bit:=  tPointer_Struct.tByte_Bit;
        tStartAdresse:= DWORD_TO_INT(SHR(IN := tByte_Bit AND 16#00ffffff, N := 3));



    // Daten von E&H lesen
    InstandzDB_P_RCV(EN_R:= true
                    ,R:= false
                    ,LADDR:= PEW_Start
                    ,DB_NO:= tDB_Nummer
                    ,DBB_NO:= tStartAdresse);
        Dummy_Bool:= InstandzDB_P_RCV.NDR;
        Dummy_Bool:= InstandzDB_P_RCV.ERROR;
        Dummy_INT:=  InstandzDB_P_RCV.LEN;
        Dummy_Word:= InstandzDB_P_RCV.STATUS;

 
 
 
 
 
 
 
// Datenausgabe
    // SWG70.Temperatur
    tMoveWord:= WORD_TO_BLOCK_DB(INT_TO_WORD(tDB_Nummer)).DD[tStartAdresse + 7];
    DatenAusgabe.SWG70.Temperatur:= tMoveReal;
    // SWG70.SignalPegel
    tMoveWord:= WORD_TO_BLOCK_DB(INT_TO_WORD(tDB_Nummer)).DD[tStartAdresse + 11];
    DatenAusgabe.SWG70.SignalPegel:= tMoveReal;

    // Sensor_1.Strom_Analog
    tMoveWord:= WORD_TO_BLOCK_DB(INT_TO_WORD(tDB_Nummer)).DD[tStartAdresse + 27];
    DatenAusgabe.Sensor.Strom_Analog:= tMoveReal;
    // Sensor_1.PV
    tMoveWord:= WORD_TO_BLOCK_DB(INT_TO_WORD(tDB_Nummer)).DD[tStartAdresse + 31];
    DatenAusgabe.Sensor.Durchfluss:= tMoveReal;
    // Sensor_1.SV
    tMoveWord:= WORD_TO_BLOCK_DB(INT_TO_WORD(tDB_Nummer)).DD[tStartAdresse + 35];
    DatenAusgabe.Sensor.Menge_Netto:= tMoveReal;
    // Sensor_1.TV
    tMoveWord:= WORD_TO_BLOCK_DB(INT_TO_WORD(tDB_Nummer)).DD[tStartAdresse + 39];
    DatenAusgabe.Sensor.Menge_vorwaerts:= tMoveReal;
    // Sensor_1.QV
    tMoveWord:= WORD_TO_BLOCK_DB(INT_TO_WORD(tDB_Nummer)).DD[tStartAdresse + 43];
    DatenAusgabe.Sensor.Menge_rueckwaerts:= tMoveReal;
 
 

OK:= true;
END_FUNCTION_BLOCK
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Moin,
ich habe heute morgen mir das ganze mal genauer angeschaut, was ich da mal zusammengeschrieben hatte: Meisten habe ich mir angewöhnt immer ein paar Kommentare ran zu schreiben...

Zum Code: Die SPS sendet als String ein paar Daten - wie z.B. Adresse vom Teilnehmer, Funktionscode (Ist Vorgabe von E&H) und ich bekomme dann eine Antwort. Diesen String zerlege ich um die einzelnen Daten daraus zu bekommen (Temperatur, Durchfluss usw.).


Code:
// *********************************************************************************************************************************
// *** EndressHauser LAN
// *********************************************************************************************************************************


// *********************************************************************************************************************************
// *** UDT für Datenausgabe
// *********************************************************************************************************************************

TYPE UDT_EuH
    STRUCT
        SWG70:                      STRUCT
            Temperatur:                 REAL;               // Temperatur Elektronik in °C
            SignalPegel:                REAL;               // Singalpegel in dB
                                    END_STRUCT;
       
        Sensor:                     STRUCT
            Strom_Analog:               REAL;               // in mA
            Durchfluss:                 REAL;               // in L/Min
            Menge_Netto:                REAL;               // in m³ (vorwärts - rückwärts)
            Menge_vorwaerts:            REAL;               // in m³
            Menge_rueckwaerts:          REAL;               // in m³
                                    END_STRUCT;
    END_STRUCT
END_TYPE





// *********************************************************************************************************************************
// *** FB E&H
// *********************************************************************************************************************************

FUNCTION_BLOCK EndressHauser
 TITLE = 'Signalaustausch E&H'
 AUTHOR: Gollasch
 VERSION: '1.0'

VAR_INPUT
    PEW_Start:                  INT;                        // erste P-Adresse
    PAW_Start:                  INT;                        // erste P-Adresse
END_VAR


VAR_IN_OUT
END_VAR


VAR_OUTPUT
    DatenAusgabe:                UDT_EuH;
END_VAR


VAR
    InstandzDB_P_RCV:           P_RCV;
    InstandzDB_P_SEND:          P_SEND;

    SendeDaten01:               BYTE;   // Adresse E&H
    SendeDaten02:               BYTE;   // Funktionscode
    SendeDaten03:               WORD;   // Startadresse
    SendeDaten04:               WORD;   // DatenLänge
    SendeDaten05:               WORD;   // Checksumme
    SendeDaten06:               INT;    // Länge Sendedaten
   
    vBlinker:                   Blinker;
   
    Daten:                      ARRAY[0..300] OF BYTE;
END_VAR


VAR_TEMP
    tPointer_Struct:        STRUCT
        tID:                    BYTE;                               // ID für ANY (10 hex = S7-Format)
        tDataTyp:               BYTE;                               // ID für ANY (02 hex = es wird mit Bytes gearbeitet)
        tLaenge:                INT;                                // Anzahl Daten
        tDB_Nummer:             INT;                                // DB der im ANY Pointer benutzt wird
        tByte_Bit:              DWORD;                              // Byte und Bit
                            END_STRUCT;                             //
    tPointer AT tPointer_Struct: ANY;                               // ANY-Pointer zur Struktur

    tID:                    BYTE;                                   // ID für ANY (10 hex = S7-Format)
    tDataTyp:               BYTE;                                   // ID für ANY (02 hex = es wird mit Bytes gearbeitet)
    tLaenge:                INT;                                    // Anzahl Daten
    tDB_Nummer:             INT;                                    // DB der im ANY Pointer benutzt wird
    tByte_Bit:              DWORD;                                  // Byte und Bit
    tStartAdresse:          INT;                                    // tByte_Bit ind Startadresse umgerechnet

    tMoveReal:              REAL;
    tMoveWord AT tMoveReal: DWORD;

    tSchleife:              INT;
    tNeuWert:               BOOL;

    tSendetakt:             BOOL;
    tEmpfang:               BOOL;

    Dummy_Bool:             BOOL;
    Dummy_INT:              INT;
    Dummy_Word:             WORD;
    Dummy_DWord:            DWORD;
    Dummy_Real:             REAL;
    Dummy_Time:             TIME;
END_VAR


LABEL
END_LABEL






BEGIN


// Takt zum senden
    vBlinker(iZeit_EIN:= t#1s
            ,iZeit_AUS:= t#5s);
        tSendetakt:= vBlinker.oAusgang;
        Dummy_Time:= vBlinker.oRestZeit_EIN;
        Dummy_Time:= vBlinker.oRestZeit_AUS;





// Daten an E&H senden
    // SendeCode an E&H
    SendeDaten01:= B#16#01;     // Adresse vom WirelessHart-Fieldgate SWG70
    SendeDaten02:= B#16#04;     // Funktionscode
    SendeDaten03:= W#16#0000;   // Startadresse
    SendeDaten04:= W#16#0030;   // DatenLänge (28 Byte)
    SendeDaten05:= W#16#F01E; //F1C3;   // Checksumme
    SendeDaten06:= 8;           // Länge Sendedaten
 
 
    // Pointer für DB und Startadresse
    tPointer:= SendeDaten01;                                               // DB auslesen
        tID:=        tPointer_Struct.tID;
        tDataTyp:=   tPointer_Struct.tDataTyp;
        tLaenge:=    tPointer_Struct.tLaenge;
        tDB_Nummer:= tPointer_Struct.tDB_Nummer;
        tByte_Bit:=  tPointer_Struct.tByte_Bit;
        tStartAdresse:= DWORD_TO_INT(SHR(IN := tByte_Bit AND 16#00ffffff, N := 3));

        tLaenge:= SendeDaten06;


    // nach E&H senden
    InstandzDB_P_SEND(REQ:= tSendetakt
                     ,R:= false
                     ,LADDR:= PAW_Start
                     ,DB_NO:= tDB_Nummer
                     ,DBB_NO:= tStartAdresse
                     ,LEN:= tLaenge);
        Dummy_Bool:= InstandzDB_P_SEND.DONE;
        Dummy_Bool:= InstandzDB_P_SEND.ERROR;
        Dummy_Word:= InstandzDB_P_SEND.STATUS;
 







// Daten von E&H lesen
    // BD und Startadresse suchen
    tPointer:= Daten;                                             // DB auslesen
        tID:=        tPointer_Struct.tID;
        tDataTyp:=   tPointer_Struct.tDataTyp;
        tLaenge:=    tPointer_Struct.tLaenge;
        tDB_Nummer:= tPointer_Struct.tDB_Nummer;
        tByte_Bit:=  tPointer_Struct.tByte_Bit;
        tStartAdresse:= DWORD_TO_INT(SHR(IN := tByte_Bit AND 16#00ffffff, N := 3));



    // Daten von E&H lesen
    InstandzDB_P_RCV(EN_R:= true
                    ,R:= false
                    ,LADDR:= PEW_Start
                    ,DB_NO:= tDB_Nummer
                    ,DBB_NO:= tStartAdresse);
        Dummy_Bool:= InstandzDB_P_RCV.NDR;
        Dummy_Bool:= InstandzDB_P_RCV.ERROR;
        Dummy_INT:=  InstandzDB_P_RCV.LEN;
        Dummy_Word:= InstandzDB_P_RCV.STATUS;

 
 
 
 
 
 
 
// Datenausgabe
    // SWG70.Temperatur
    tMoveWord:= WORD_TO_BLOCK_DB(INT_TO_WORD(tDB_Nummer)).DD[tStartAdresse + 7];
    DatenAusgabe.SWG70.Temperatur:= tMoveReal;
    // SWG70.SignalPegel
    tMoveWord:= WORD_TO_BLOCK_DB(INT_TO_WORD(tDB_Nummer)).DD[tStartAdresse + 11];
    DatenAusgabe.SWG70.SignalPegel:= tMoveReal;

    // Sensor_1.Strom_Analog
    tMoveWord:= WORD_TO_BLOCK_DB(INT_TO_WORD(tDB_Nummer)).DD[tStartAdresse + 27];
    DatenAusgabe.Sensor.Strom_Analog:= tMoveReal;
    // Sensor_1.PV
    tMoveWord:= WORD_TO_BLOCK_DB(INT_TO_WORD(tDB_Nummer)).DD[tStartAdresse + 31];
    DatenAusgabe.Sensor.Durchfluss:= tMoveReal;
    // Sensor_1.SV
    tMoveWord:= WORD_TO_BLOCK_DB(INT_TO_WORD(tDB_Nummer)).DD[tStartAdresse + 35];
    DatenAusgabe.Sensor.Menge_Netto:= tMoveReal;
    // Sensor_1.TV
    tMoveWord:= WORD_TO_BLOCK_DB(INT_TO_WORD(tDB_Nummer)).DD[tStartAdresse + 39];
    DatenAusgabe.Sensor.Menge_vorwaerts:= tMoveReal;
    // Sensor_1.QV
    tMoveWord:= WORD_TO_BLOCK_DB(INT_TO_WORD(tDB_Nummer)).DD[tStartAdresse + 43];
    DatenAusgabe.Sensor.Menge_rueckwaerts:= tMoveReal;
 
 

OK:= true;
END_FUNCTION_BLOCK

Danke für die Mühe... wie von mir vermutet hast du hier scheinbar den kompletten Vorgang selbst in SCL programmiert, das übersteigt bei weitem mein Können und daher kann ich damit leider nicht allzu viel anfangen. Ich wäre schon happy wenn der Standard aus dem TIA funktionieren würde. ;) Aber wie du siehst habe ich bereits hier zu kämpfen.
 
Ich habe mich hier etwas ungeschickt ausgedrückt, gemeint war der Ausgangsbyte-Register in welchem meine "Wärmeanforderung" enthalten ist. Hier habe ich auf Seite.80 der Bedienungsanleitung Bezug genommen, wobei das nicht richtig ist wie mir mittlerweile aufgefallen ist, da das für Profibus gilt. Seite.87 ist hier das richtige 16Bit Register auf das ich versuchen möchte zu schreiben.Anhang anzeigen 76841
@RONIN Hallo Ronin, fällt dir hierzu noch etwas ein? Registeradresse 0 müsste beim TIA Portal Master doch laut Infosystem einer 1 entsprechen, oder? Die DATA_LEN sollte auch 1 sein, da ich ja nur die Wärmeanforderung schreiben möchte?! Ich verzweifle noch, das kann doch nicht so schwer sein.
 
Einige Dinge fallen mir beim erneuten Lesen der Beiträge auf.
  • Beitrag #1 zeigt dein "Modbus_Comm_Load"-Einstellungen. Dort ist 9600 Baud und NoParity eingestellt. Da musst du nochmal die richtigen Einstellungen treffen auch wenn du die HW-Config schon eingestellt hast. Also in deinem Fall (19200 und 2 - Even). Auch den Parameter "MODE" im IDB des "Modbus_Comm_Load" würde ich mit 4 (Halbduplex) beschreiben.
  • Den falschen DATA_PTR an "Modbus_Master" hast du ja schon behoben. Was hast du da jetzt dran? Ein Array of Word in einem Global-DB?
  • Beitrag #10 zeigt eine Einstellung von 2 Stoppbits. Ist nicht üblich. Eher 1 Stoppbit, kann das aber in der Anleitung des Gerätes auch nicht erachten.
Nachdem du den "Modbus_Comm_Load" dann erfolgreich ausgeführt hast, also Signal "Done" ohne "Error" erhalten hast, könntest du wieder die ersten Versuche starten. Konntest du überhaupt schon Daten lesen? Vor dem Schreiben würde ich immer erstmal versuchen zu lesen.

Ich würde mal versuchen Modbus-Funktion 1 (Read Coils) auszuführen. Zum Beispiel MODE 0, DATA_ADDR 1, LEN 1.
Erst wenn der Befehl mal durchläuft ohne das der Modbus_Master einen Fehler ausspuckt, dann würde ich weitergucken.

Wie gesagt, wenn du einen RS485/USB-Adapter hättest, dann könntest du den Verkehr der aus der CPU kommt beobachten. Damit wären so einfach grundlegende Dinge wie "A/B vertauscht" schon mal weg. Du könntest ggf. den CPU mit einem ModbusSlave-Simulator am PC kommunizieren lassen oder von PC mit einem ModbusMaster-Programm versuchen mit deinem Gerät zu sprechen. Das macht die Fehlersuche deutlich einfacher. Vor allem wenn man dann zwei Geräte (PC und SPS) nicht mit dem Slave sprechen können, dann kann man die Suche im SPS-Code mal beiseite legen.

Ich hab mit einer 1200 und einem CB1241 mal schnell ein Beispiel zusammengeschrieben und getestet. Das funktioniert hier mit dem PC und RS485-Adapter als Modbus-Slave. Das kannst du vielleicht als Anhaltspunkt nehmen.
 

Anhänge

  • S71200_ModbusRTU_Master_Beispiel.zip
    1,1 MB · Aufrufe: 0
Zuletzt bearbeitet:
Zurück
Oben