oscat.lib > Modulentwicklung / Module Development

Danfoss RS485

<< < (2/5) > >>

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):


--- Code: ---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
--- Ende Code ---


--- Code: ---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);
--- Ende Code ---

Baustein für jeden Fu aufrufen:


--- Code: ---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
--- Ende Code ---


--- Code: ---(*## 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;
--- Ende Code ---

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

Navigation

[0] Themen-Index

[#] Nächste Seite

[*] Vorherige Sete

Zur normalen Ansicht wechseln