Danfoss RS485

Begonnen von Wu Fu, 21. Mai 2009, 23:30:55

Vorheriges Thema - Nächstes Thema

0 Mitglieder und 4 Gäste betrachten dieses Thema.

Wu Fu

Hallo zusammen,
hat schon man jemand eine Kommunikation zwischen einem Frequenzumformer der Firma Danfoss und einer SPS über RS485 realisiert. Eigentlich müsste das ganze über Modbus RTU möglich sein. Ist halt ein riesiger Programmieraufwand.
Ich verlink mal das Handbuch von Danfoss, ab Seite 131 ist die Schnittstelle beschrieben.
http://mcliterature.danfoss.com/WebPublish/doc_MG11B903.pdf
Wäre schön, wenn schon jemand Erfahrung gesammelt hat und diese evtl. mitteilen möchte. :D
mfg

mg

Hallo Hugo

Ich habe auch schon in so machen anderen Foren gesehen, daß Du daran interessiert wärst. (Wenn auch dieser "Hugo" Du bist)
... ICH AUCH ... sehr sogar.

Hab dzt WAGO in Verwendung ... ist aber immer ein Blindflug ohne SourceCode.

Dorfmeister

Du brauchst zuerst einen MODBUS-Treiber, dieser ist abhängig von Deiner (Ziel)-Hardware. Für den WAGO 750-841 gibt es IMHO eine passende Lib. Du brauchst natürliche noch eine serielle Schnittstellenkarte 750-65x.

Das Beschreiben und Auslesen der einzelnen Register sollte relativ einfach sein.

Falls es für Deine Ziel-Hardware keinen MODBUS-Treiber gibt, sieht es problematischer aus. Denn ein hardwareunabhängiger Treiber ist mir nicht bekannt. Generell ist es so, dass die CoDeSys-Hardwarehersteller die Lib bei 3S einkaufen und die Lib natürlich entsprechend so "manipulieren" das sie nur auf die eigene Hardware passt.

Wichtig noch; Deine Ziel-Hardware ist der Master bzw. Client und der FU ist der Slave bzw. Server.


Wu Fu

Nee, bin leider nicht "der" Hugo. ;)
In welchen Foren hast du den schon Beiträge dieser Art gelesen? Man ist ja ständig auf der Suche nach neuen Informationen.
Als speziell würde mich die Verbindung zwischen Wago und Danfoss interessieren. Wie du schon sagst, wird ModBus unterstützt.
Ich hab auch schon ein paar Anwendungen an SCADA-Systeme damit realisiert. Allerdings hatten diese dann eine Modbustreiber und ich musste die Adresse die im Programm verwendet werden angeben und danach konnten die Werte dann gelesen oder geschrieben werden.
Die Wago war quasi der Slave, aber in diesem Fall sollte die SPS der Master sein. Weiß leider nicht so recht, wie das Anzustellen ist bzw. wie auf die Register zugegriffen werden kann.
Hat vielleicht jemand ein kleines Anwendungsbeispiel oder ähnliches schon realisiert?
mfg


mg

Anwendungsbeispiel haben die bei WAGO. Du brauchst wie gesagt eine 750-65x/* Karte. Rs485 beim Danfoss - was ich weiß. Du kannst ja mal beim Support nachfragen, die helfen Dir gerne. Ich habe noch kein Danfoss-Gerät damit aufgeschalten aber schon ein paar andere mit Modbus RS485. Es geht. Die Lösung/Lib von Wago ist ein bischen chaotisch. Deswegen und auch aus anderen Gründen hätte ich gerne eine OpenSource-Lib für das Ganze. Aber das sieht eher so aus, daß es keiner hergibt. Und/Oder es wirklich noch niemand außer die Steuerungshersteller selbst geschreiben haben.

PS: Mit "Hugo" habe ich nicht Wu Fu gemeint sondern einen der Administratoren des Forums

Wu Fu

Ich glaub das Anwendungsbeispiel hab ich gefunden.
Jetzt brauch ich nur nochmal Zeit mich ausgiebig damit zu befassen.  ::)
Mit einer Lib für RS485 kann ich dir aber leider auch nicht weiter helfen.
mfg

PGmonster

Hallo Wu Fu,

ich habe mit schon mal eine Verbindung zu zwei Danfoss FC300 über Modbus RTU (RS485) aufgebaut. Allerdings nur zum Test auf dem Schreibtisch. Ich habe mir damals zwei Bausteine geschrieben:

Der erste Baustein wird in einer zyklischen Task aufgerufen und ist für die Kommunikation verantwortlich.
Der zweite Baustein wird irgendwo im Programm aufgerufen und stellt die Status- und Steuerbits zur Verfügung.

Hier mal der Code:

Baustein in Zyklischer Task (bei mir 10ms):

PROGRAM Com_Danfoss
VAR
ModbusMaster: MODBUSMASTER_RTU;
i: BYTE := 1; (*Schleifenzähler*)
Slaveadresse: BYTE; (*Slaveadresse in der Schleife*)
Aktion_RW: BYTE; (*Aktion lesen=0 / schreiben=1 / nächster Slave=2*)
FunctionCode: BYTE;
StartAddress: WORD;
NumberOfPoints: WORD;
StartFunction: BOOL;
Fehler: BYTE;
SlaveError: ARRAY [1..SlaveAnzahl] OF enumMB_ERROR;
SlaveData: ARRAY [1..SlaveAnzahl] OF SlaveData;
FU_Data: ARRAY [1..SlaveAnzahl] OF FU_Data;
xxB: POINTER TO BYTE;
test: BOOL :=FALSE;
END_VAR
VAR CONSTANT
SlaveAnzahl: BYTE := 7; (*wenn Änderung, dann Initalwerte anpassen*)
SlaveAdr: ARRAY [1..SlaveAnzahl] OF BYTE := 1,2,3,4,5,6,7;
SlaveParameter: ARRAY [1..SlaveAnzahl] OF AktParRW := 7(( Lesen:=( FunctionCode:=1,
StartAddress:=32,
NumberOfPoints:=32),
Schreiben:=( FunctionCode:=15,
StartAddress:=0,
NumberOfPoints:=32)));
(*Schnittstelle für Danfoss FU*)
ComPort: BYTE := 2;
ComBaudrate: COM_BAUDRATE := BAUD_19200;
ComParity: COM_PARITY := PARITY_EVEN;
ComStopbits : COM_STOPBITS := STOPBITS_1;
ComBytesize : COM_BYTESIZE := BS_8;
ComFlowControl: COM_FLOW_CONTROL := HALFDUPLEX;
ComTimeOut: TIME := t#20ms;
END_VAR


CASE Aktion_RW OF
(*Daten vom Slave lesen*)
0: Slaveadresse := SlaveAdr[i]; (*Slaveadresse*)
FunctionCode := SlaveParameter[i].Lesen.FunctionCode; (*Funktionscode für lesen*)
StartAddress := SlaveParameter[i].Lesen.StartAddress; (*Startadresse Statuswort*)
NumberOfPoints := SlaveParameter[i].Lesen.NumberOfPoints; (*Bereichslänge*)

IF NOT StartFunction THEN (*Warte auf Antwort vom Slave*)
IF SlaveData[i].Lesen.Data[1] = FunctionCode (*Funktionscode in Antwort gleich*)
AND SlaveData[i].Lesen.Data[0] = Slaveadresse (*Slaveadresse in Antwort gleich*)
AND NOT BYTE_TO_BOOL(Fehler) (*kein Fehler*)
THEN
(*Zustandswort eintragen*)
xxB := ADR(FU_Data[i].Zustandswort); (*Pointer für Zielbits*)
xxB^ := SlaveData[i].Lesen.Data[3];
xxB := xxB + SIZEOF(SlaveData[i].Lesen.Data[3]);
xxB^ := SlaveData[i].Lesen.Data[4];
(*Istwert eintragen*)
xxB := ADR(FU_Data[i].Istwert); (*Pointer für Zielbits*)
xxB^ := SlaveData[i].Lesen.Data[5];
xxB := xxB + SIZEOF(SlaveData[i].Lesen.Data[5]);
xxB^ := SlaveData[i].Lesen.Data[6];

Aktion_RW := 1; (*dann schreiben*)
(* StartFunction := 1;*)
test := 0;
RETURN;
ELSE
IF BYTE_TO_BOOL(Fehler) AND test
THEN SlaveError[i] := Fehler;
Aktion_RW := 2;
END_IF;
END_IF;
StartFunction := 1;
test := 1;
END_IF;

(*Daten zum Slave schreiben*)
1: Slaveadresse := SlaveAdr[i]; (*Slaveadresse*)
FunctionCode := SlaveParameter[i].Schreiben.FunctionCode; (*Funktionscode für schreiben*)
StartAddress := SlaveParameter[i].Schreiben.StartAddress; (*Startadresse Steuerwort*)
NumberOfPoints := SlaveParameter[i].Schreiben.NumberOfPoints; (*Bereichslänge*)

IF SlaveData[i].Lesen.Data[1] = FunctionCode (*Funktionscode in Antwort gleich*)
AND SlaveData[i].Lesen.Data[0] = Slaveadresse (*Slaveadresse in Antwort gleich*)
AND NOT BYTE_TO_BOOL(Fehler) (*kein Fehler*)
THEN
(*Steuerwort eintragen*)
xxB := ADR(FU_Data[i].Steuerwort); (*Pointer für Zielbits*)
SlaveData[i].Schreiben.Data[0] := xxB^;
xxB := xxB + SIZEOF(SlaveData[i].Schreiben.Data[0]);
SlaveData[i].Schreiben.Data[1] := xxB^;
(*Sollwert eintragen*)
xxB := ADR(FU_Data[i].Sollwert); (*Pointer für Zielbits*)
SlaveData[i].Schreiben.Data[2] := xxB^;
xxB := xxB + SIZEOF(SlaveData[i].Schreiben.Data[2]);
SlaveData[i].Schreiben.Data[3] := xxB^;

Aktion_RW := 2; (*dann schreiben*)
(* StartFunction := 1;*)
RETURN;
ELSE
IF BYTE_TO_BOOL(Fehler)
THEN SlaveError[i] := Fehler;
Aktion_RW := 2;
END_IF;
StartFunction := 1;
END_IF;

(*Nächster Slave*)
2: IF NOT BYTE_TO_BOOL(Fehler)
THEN  SlaveError[i] := Fehler;
Fehler := 0;
END_IF;
IF NOT StartFunction
THEN IF i >= SlaveAnzahl (*wenn letzter Slave erreicht*)
THEN i := 1; (*dann wieder erster Slave*)
ELSE i := i + 1; (*sonst nächster Slave*)
END_IF;
Aktion_RW := 0; (*danach lesen*)
test := 0;
END_IF;
END_CASE;

(*Modbusmaster für die Kommunikation mit den Slaves*)
ModbusMaster(
SlaveAddress:= Slaveadresse,
FunctionCode:= FunctionCode,
StartAddress:= StartAddress,
NumberOfPoints:= NumberOfPoints,
bCOM_PORT:= ComPort, (*VAR CONSTANT*)
cbCOM_BAUDRATE:= ComBaudrate, (*VAR CONSTANT*)
cpCOM_PARITY:= ComParity, (*VAR CONSTANT*)
csCOM_STOPBITS:= ComStopbits, (*VAR CONSTANT*)
cbsCOM_BYTESIZE:= ComBytesize, (*VAR CONSTANT*)
cfCOM_FLOW_CONTROL:= ComFlowControl, (*VAR CONSTANT*)
TimeOut:= ComTimeOut, (*VAR CONSTANT*)
StartFunction:= StartFunction,
ReceiveBuffer:= SlaveData[i].Lesen,
SendData:= SlaveData[i].Schreiben,
Error=> Fehler);


Baustein für jeden Fu aufrufen:

FUNCTION_BLOCK Schnittstelle_Danfoss
VAR_INPUT
(* Festsollwertanwahl_LSB: BOOL;
Festsollwertanwahl_MSB: BOOL;
Keine_DC_Bremse: BOOL;
Kein_Freilaufstopp: BOOL;*)
Kein_Schnellstopp: BOOL;
(* Keine_Freq_speichern: BOOL;*)
Start: BOOL;
Reset: BOOL;
JOG: BOOL;
(* Rampe_2: BOOL;
Daten_gueltig: BOOL;
Relais_1: BOOL;
Relais_2: BOOL;
Parametersatzwahl_LSB: BOOL;
Parametersatzwahl_MSB: BOOL;*)
Reversierung: BOOL;
rSollwert: REAL;
END_VAR
VAR_OUTPUT
Regler_bereit: BOOL;
Frequenzumrichter_betriebsbereit: BOOL;
Sicherheitsverriegelung: BOOL;
Alarm: BOOL;
Warnung: BOOL;
Ist_gleich_Soll: BOOL;
Autobetrieb: BOOL;
In_Freq_Bereich: BOOL;
Motor_ein: BOOL;
Spannungswarnung: BOOL;
Stromgrenze: BOOL;
Warnung_Uebertemp: BOOL;
rIstwert: REAL;
END_VAR
VAR
rSoll: REAL;
END_VAR
VAR_IN_OUT
FU_Data: FU_Data;
END_VAR


(*## Daten zu FU schreiben ##*)
FU_Data.Steuerwort.0 := FALSE; (*Festsollwertanwahl_LSB*)
FU_Data.Steuerwort.1 := FALSE; (*Festsollwertanwahl_MSB*)
FU_Data.Steuerwort.2 := TRUE; (*Keine_DC_Bremse*)
FU_Data.Steuerwort.3 := TRUE; (*Kein_Freilaufstopp*)
FU_Data.Steuerwort.4 := Kein_Schnellstopp;
FU_Data.Steuerwort.5 := TRUE; (*Keine_Freq_speichern*)
FU_Data.Steuerwort.6 := Start;
FU_Data.Steuerwort.7 := Reset;
FU_Data.Steuerwort.8 := JOG;
FU_Data.Steuerwort.9 := FALSE; (*Rampe_2*)
FU_Data.Steuerwort.10 := TRUE; (*Daten_gueltig*)
FU_Data.Steuerwort.11 := FALSE; (*Relais_1*)
FU_Data.Steuerwort.12 := FALSE; (*Relais_2*)
FU_Data.Steuerwort.13 := FALSE; (*Parametersatzwahl_LSB*)
FU_Data.Steuerwort.14 := FALSE; (*Parametersatzwahl_MSB*)
FU_Data.Steuerwort.15 := Reversierung;

(*Engangsignal auf Grenzwerte begrenzen*)
IF rSollwert > 100.0
THEN rSoll := 100.0;
ELSE IF rSollwert < 0.0
THEN rSoll := 0.0;
ELSE rSoll := rSollwert;
END_IF;
END_IF;
(*FU_Sollwert berechnen*)
FU_Data.Sollwert := REAL_TO_WORD(rSoll*163.8375);

(*## Daten von FU lesen ##*)
Regler_bereit := FU_Data.Zustandswort.0;
Frequenzumrichter_betriebsbereit := FU_Data.Zustandswort.1;
Sicherheitsverriegelung := FU_Data.Zustandswort.2;
Alarm := FU_Data.Zustandswort.3;
Warnung := FU_Data.Zustandswort.7;
Ist_gleich_Soll := FU_Data.Zustandswort.8;
Autobetrieb := FU_Data.Zustandswort.9;
In_Freq_Bereich := FU_Data.Zustandswort.10;
Motor_ein := FU_Data.Zustandswort.11;
Spannungswarnung := FU_Data.Zustandswort.13;
Stromgrenze := FU_Data.Zustandswort.14;
Warnung_Uebertemp := FU_Data.Zustandswort.15;

(*FU_Istwert berechnen*)
rIstwert := FU_Data.Istwert/163.8375;


Der Code beider Bausteine ist noch nicht ausgereift, aber vielleich hilft er ja jemandem.
Ich bin für Kritik, Verbesserungen und Anregungen offen

Grüße

Tobi


Wu Fu

Hi Tobi,

Danke für deine Antwort.
Hört sich sehr gut an. Ich werde das auf jedefall testen, wenn ich wieder die Möglichkeit bzw den Fu dazu habe. ;D
Wir setzen für gewöhnlich die HVAC-Modelle FC100 ein, aber ich denke beim Protokoll wird da nicht soviel Unterschied sein.
Welche Bibliotheken muss ich den für dein Beispiel laden?

Grüße

Daniel

PGmonster

Hallo Daniel,

die Bausteine waren eigentlich für eine Anlage mit sieben FC100 FuÃ,´s gedacht. Sieht man noch im Code vom Com_Danfoss bei den Var Constant. Ich hatte aber nur zwei FC300 zum Testen auf dem Schreibtisch.
Ich habe mal ein kleines Projekt angehängt, damit die Benutzung der Bausteine klarer wird.
Im Com_Danfoss bei den Var Constant müssen die SlaveAnzahl und die SlaveAdressen angegeben werden.
Bei SlaveParameter reicht es eigentlich die 7 nach dem := auf die Slaveanzahl zu setzen (hier sind es eben sieben).
Man muss noch die Modb_l05.lib von Wago einbinden.

Feedback erwünscht (auch von den Oscat Leuten!)

Grüß

Tobi

PS: Die Kommunikation läuft bei mir, aber im FU zeigt mir der Busfehlerzähler bei Parametrierung von mehr als einem Slave ständig Busfehler an. ???

[gelöscht durch Administrator]

Wu Fu

Hallo Tobi,
sieht auf jeden Fall sehr vielversprechend aus. Aber ein paar Fragen hab ich momentan noch.
Welche Angaben wo im Steuer- bzw. Zustandswort hinterlegt sind hab ich gesehen (ab Seite 166 http://mcliterature.danfoss.com/WebPublish/doc_G_1_MG61B503.pdf). Aber woher du weißt wo das Steuer- bzw. Zustandswortes liegt ist mit leider nicht ganz klar. Stehen die auch im Handbuch und hab ich die Angaben einfach übersehen? Wäre es z. B. auch möglich die Parameter 509-532 (ab Seite 174) auszulesen?
Daten werden ja in rauen Mengen vom FU geliefert.  :D
Welche Anwendung hattest du denn mit 7 Frequenzumformern geplant?
Sobald ich getestet habe gebe ich dir gerne Bescheid.

Grüße

Daniel

PGmonster

Hallo Daniel,

schau mal hier http://mcliterature.danfoss.com/WebPublish/downloadPub.do?no=0.
Auf Seite 141 stehen die Adressen für Steuer- und Zustandswort (Vergleiche Com_Danfoss.SlaveParameter...)
Man kann auch noch andere Parameter auslesen. Das wollte ich eigentlich auch noch einfügen (z.B. Stör- und Warnmeldugnen, aktuelle Leistung, ...). Nur da bin ich mir noch nicht schlüssig wie ich das am besten mache.
Zyklisch mit dem STW und ZSW oder azyklisch z.B. nur wenn Stör- oder Warnmeldungen anstehen oder einfach nur auf Anforderung.
Da kann man sich wirklich austoben.
Das ganze war bzw. ist für eine Klimaanlage mit sechs 30kw und einem 45 kW Lüfter. Momentan sind diese noch über alte Kompaktregler angesteuert. Wollte ich aber mit auf die Wago SPS hängen die schon andere Regelkreise regelt.

Grüße

Tobi

Wu Fu

Hallo Tobi,
ich kann leider den Link nicht öffnen. Kannst du bitte kurz erklären, um welches Dokument es sich handelt?
Hab mir die Abfrageart so vorgestellt, dass Anzeigen wie Betriebszeit, aktuelle Leistung, etc. nur abgefragt werden wenn die jeweilige Visualisierungsseite betätigt wird. Anscheinend gibts auch ein Alarmwort, dieses evtl. nur abfragen, wenn  das Alarmrelais eine Störung ausgibt.
Ich glaube nicht, dass alles zyklisch abgefragt werden sollte, da wahrscheinlich (je nach FU-Anzahl) schon einiges an Daten zusammenkommt.
Ich denke genau wird man s erst in der Parxis sehen, was gebraucht wird und was nicht.

Grüße
Daniel

PGmonster

Hallo Daniel,

dieser Link sollte funktionieren: http://mcliterature.danfoss.com/WebPublish/doc_MG11B903.pdf
Das ist das Projektierungshandbuch für den FC100.
Bezüglich der weiteren Abfragen: Hast Du vor wenn dann immer die gleichen Parameter abzufragen oder sollten die variabel sein (z.B. immer Betriebszeit und Leistung und ...)? Das sollte relativ einfach durch Erweiterung des Sprungverteilers gehen. Ich denke noch mal drüber nach.

Gruß

Tobi

Wu Fu

Hi Tobi,

leider kann ich denk Link wieder nicht öffnen. Müsste ja dieselbe Adresse sein, die ich in meinem ersten Beitrag verlinkt habe. Denn kann ich leider auch nicht mehr öffnen. :-\
Das Projektierungshandbuch habe ich im Beitrag vom 29 Juni verlinkt. Das ist aber leider nicht dasselbe. O man, und in keiner Doku konnte ich die Adressen finden. Bei dir ist das Statuswort auf Adresse 32 und das Steuerwort auf Adresse 0, oder?
Ja, wenn dann möchte ich immer die gleichen Parameter abfragen. Vielleicht könnte man ja verschieden Parameter in verschieden Funktionsblöcke "packen" und nur die benötigten FBs einbinden. Ich hoffe ich habe deine Frage richtig verstanden.

Grüße

Daniel

dalbi

Hallo,

jetzt probiere ich es mal http://www.danfoss.com/Germany/BusinessAreas/DrivesSolutions/Documentation/tecnicalLiterature.htm auf der Seite VLT HVAC Drive FC 100 wählen "Projektierungshandbuch".

Gruss Daniel