Codesys Netvar nutzen

Hallo,

Ich habe in den letzten Tagen ein wenig mit den Netvars experimentiert.
Ich habe auch schon erste Erfolge erzielen können. Dabei sind zwei Skripte entstanden.
Um das ganze Produktiv zu testen fehlt mir die Umgebung. Das Haus zum System wird erst im Frühjahr gebaut.
Erstellt und getestet habe ich das alles auf einem Raspberry Pi mit der aktuellen Beta und dem 750-881 Controller von Wago.

Nun zum Lesen von Variablen:
Man muss zuerst ein UDP Socket in den I/O Instanzen erstellen. Sende und Empfangsport sind Standardmäßig 1202. Ob man beim Sende-Host den kompletten Broadcast (255.255.255.255) verwendet, oder die IP-Adresse des Controllers ist egal. Man muss es nur in der SPS genauso machen. Als nächstes muss eine RegisterVariable erstellt werden, welche als Übergeordnete Instanz den UDP Socket und als Ziel folgendes Skript hat.

<?

//Variablenlistenerkennung COB-ID
$cobID=1;





//In der Folgenden Funktion müssen alle Variablen der Variablenliste (Codesys) in der Richtigen Reihenfolge abgefragt werden!
//Dazu einfach die Funktionen writeInt und writeBool nacheinander aufrufen
//Die Richtige Reihenfolge und Anzahl ist wichtig!!      
function WerteSchreiben($daten,&$tmp){


//Der 4. Funktionsparameter bei writeInt gibt an ob es ein signed oder unsignet Integer ist.
//1=signed, 0=unsigned


//writeBool(12345,$tmp,$daten);
//writeInt(12345,$tmp,$daten,0);





}





$tmp=0;
//Variable wird Für den Offset im Array verwendet


if ($_IPS['SENDER'] == "RegisterVariable")
{
    // bereits im Puffer der Instanz vorhandene Daten in $data kopieren
    $data  = RegVar_GetBuffer($_IPS['INSTANCE']);
    // neu empfangene Daten an $data anhängen
    $data .= $_IPS['VALUE'];

	//Daten in Hex umwandeln und in ein Array Zerschneiden
    $hex=bin2hex($data);
    $arr = str_split($hex, 1);
    

    if(hexdec($arr[17])==$cobID){
    //Cob-ID wird überprüft
    WerteSchreiben($arr,$tmp);
    }

    // Lerren Inhalt im Puffer der RegisterVariable-Instanz speichern
    RegVar_SetBuffer($_IPS['INSTANCE'], '');
 	}




function writeInt($variable,&$adresszaehler,$daten,$Typ){
	//low-,high-Byte Tausch. Im Datenbereich 40 Stehen Die Ersten Variablen.
	$value = $daten[42+$adresszaehler].$daten[43+$adresszaehler].$daten[40+$adresszaehler].$daten[41+$adresszaehler];
	$decval=hexdec($value);
	
	//Überprüfung ob INT oder UINT, Werte in Variablen Schreiben
	if (($Typ == 1)&&($decval>32766)){
	//Variable Umwandeln und Schreiben
	SetValueInteger($variable,($decval-65536));
	}
	else{
	SetValueInteger($variable,$decval);
	}
	//Offset erhöhen
	$adresszaehler=$adresszaehler+4;
}



function writeBool($variable,&$adresszaehler,$daten){
	//low-,high-Byte Tausch. Im Datenbereich 40 Stehen Die Ersten Variablen.
	$value = $daten[41+$adresszaehler];
	//Variable Umwandeln und Schreiben
	SetValueBoolean($variable,hexdec($value));
	//Offset erhöhen
	$adresszaehler=$adresszaehler+2;
}

?>

In dem Skript muss die cobID festgelegt werden. Die Variablen werden durch die Funktionsaufrufe writeBool und writeInt aus der UDP-Nachricht gelesen und anschließend in die angegebene Variable geschrieben. Die Funktionsaufrufe müssen absolut identisch zur Variablenliste sein. Sowohl in der Reihenfolge als auch in der Art der Variablen. Aktuell kann das Skript signed, unsigned Integer und Boolean.

Das Schreiben in die SPS geht mit Folgendem Skript:

<?

//UDP-Socket ID
$sID=12345; 

//Variablenlistenerkennung COB-ID
$cobID=2;



//Erstelle das Array für Header
$arr = array_fill(1, 39, '0');
//Erstelle Variablen, Headerlänge beträgt 20 Bytes
$Items=0;
$Length=20;


//Im Folgenden müssen alle Variablen der Variablenliste (Codesys) in der Richtigen Reihenfolge abgefragt werden!
//Dazu einfach die Funktionen readInt und readBool nacheinander aufrufen
//Die Richtige Reihenfolge und Anzahl ist wichtig!!

readBool(12345,$arr,$Length,$Items);
readInt(12345,$arr,$Length,$Items);







//Schreibe COB-ID, Die Anzahl der Elemente und die Größe (Anzahl Bytes),Setze Sende Zähler auf 1
$arr[18]=dechex($cobID);
$arr[26]=dechex($Items);
$arr[29]=dechex($Length);
$arr[33]=dechex(1);
//Schreibe die Identität (-3s) "Codesys spezifisch"
$arr[3]="2"; $arr[4]="d"; $arr[5]="5"; $arr[6]="3";$arr[7]="3"; $arr[8]="3";

//Array zu einer Variable verbinden
$hex=implode("",$arr);

//In Binärdaten Umwandeln
$data = hex2bin($hex);

//Daten senden
USCK_SendText($sID,$data);


function readBool($variable,&$daten,&$Laenge,&$Anzahl){
	//Variable Lesen und Umwandeln
	$value=dechex(GetValueBoolean($variable));
	//Die Daten werden an das Array angefügt
	array_push($daten, "0");
	array_push($daten, $value);
	$Laenge=$Laenge+1;
	$Anzahl=$Anzahl+1;

}

function readInt($variable,&$daten,&$Laenge,&$Anzahl){
	//Variable Lesen und Umwandeln
	$value=GetValueInteger($variable);
	$hexval=dechex($value);

	//low-,high-Byte Tausch.Die Daten werden im  an das Array angefügt
	//Für Negative Zahlen
	if($value<0){
	$value=65536+$value;
	$hexval=dechex($value);
	$split = str_split($hexval, 1);
	array_push($daten, $split[2]);array_push($daten, $split[3]);array_push($daten, $split[0]);array_push($daten, $split[1]);
	}

	//Für Positive Zahlen
	elseif ($value < 16){
	array_push($daten, "0");array_push($daten, $hexval);array_push($daten, "00");
	}
	elseif ($value < 256){
	array_push($daten, $hexval);array_push($daten, "00");
	}
	elseif ($value < 4096){
	$split = str_split($hexval, 1);
	array_push($daten, $split[1]);array_push($daten, $split[2]);array_push($daten, "0");array_push($daten, $split[0]);
	}
	else  {
	$split = str_split($hexval, 1);
	array_push($daten, $split[2]);array_push($daten, $split[3]);array_push($daten, $split[0]);array_push($daten, $split[1]);
	}
	
	
	//Werte für UDP Header Hochzählen
	$Laenge=$Laenge+2;
	$Anzahl=$Anzahl+1;
}

?>

Das Skript muss man einfach bei einer Variablenänderung ausführen. In dem Skript sind cobID, die ID des UDP Sockets und die Funktionsaufrufe analog zum Lesen einzufügen.

Ich freue mich über Feedback, Verbesserungs- und Ergänzungsvorschläge. Vor allem wie sich das ganze bei großen Variablenzahlen schlägt würde mich interessieren, da Modbus TCP damit ja stellenweis seine Probleme hat.

Geplante Ergänzungen:
-REAL\FLOAT Variablen

Cl1x

Hallo,

Ich habe die Skripte erweitert. Nun ist das Lesen und Schreiben von REAL/FLOAT Variablen möglich.

Skript zum Lesen:

<?

//Variablenlistenerkennung COB-ID
$cobID=1;





//In der Folgenden Funktion müssen alle Variablen der Variablenliste (Codesys) in der Richtigen Reihenfolge abgefragt werden!
//Dazu einfach die Funktionen writeInt und writeBool nacheinander aufrufen
//Die Richtige Reihenfolge und Anzahl ist wichtig!!      
function WerteSchreiben($daten,&$tmp){


//Der 4. Funktionsparameter bei writeInt gibt an ob es ein signed oder unsignet Integer ist.
//1=signed, 0=unsigned


//writeBool(12345,$tmp,$daten);
//writeInt(12345,$tmp,$daten,0);
//writeFloat(12345,$tmp,$daten);





}





$tmp=0;
//Variable wird Für den Offset im Array verwendet


if ($_IPS['SENDER'] == "RegisterVariable")
{
    // bereits im Puffer der Instanz vorhandene Daten in $data kopieren
    $data  = RegVar_GetBuffer($_IPS['INSTANCE']);
    // neu empfangene Daten an $data anhängen
    $data .= $_IPS['VALUE'];

	//Daten in Hex umwandeln und in ein Array Zerschneiden
    $hex=bin2hex($data);
    $arr = str_split($hex, 1);
    

    if(hexdec($arr[17])==$cobID){
    //Cob-ID wird überprüft
    WerteSchreiben($arr,$tmp);
    }

    // Lerren Inhalt im Puffer der RegisterVariable-Instanz speichern
    RegVar_SetBuffer($_IPS['INSTANCE'], '');
 	}




function writeInt($variable,&$adresszaehler,$daten,$Typ){
	//low-,high-Byte Tausch. Im Datenbereich 40 Stehen Die Ersten Variablen.
	$value = $daten[42+$adresszaehler].$daten[43+$adresszaehler].$daten[40+$adresszaehler].$daten[41+$adresszaehler];
	$decval=hexdec($value);
	
	//Überprüfung ob INT oder UINT, Werte in Variablen Schreiben
	if (($Typ == 1)&&($decval>32766)){
	//Variable Umwandeln und Schreiben
	SetValueInteger($variable,($decval-65536));
	}
	else{
	SetValueInteger($variable,$decval);
	}
	//Offset erhöhen
	$adresszaehler=$adresszaehler+4;
}


function writeBool($variable,&$adresszaehler,$daten){
	//low-,high-Byte Tausch. Im Datenbereich 40 Stehen Die Ersten Variablen.
	$value = $daten[41+$adresszaehler];
	//Variable Umwandeln und Schreiben
	SetValueBoolean($variable,hexdec($value));
	//Offset erhöhen
	$adresszaehler=$adresszaehler+2;
}




function writeFloat ($variable,&$adresszaehler,$daten){

	//low-, high-Byte Tausch
	$hex  = $daten[46+$adresszaehler].$daten[47+$adresszaehler].$daten[44+$adresszaehler].$daten[45+$adresszaehler].$daten[42+$adresszaehler].$daten[43+$adresszaehler].$daten[40+$adresszaehler].$daten[41+$adresszaehler];

	//binärdaten erzeugen
	$bin = str_pad(base_convert($hex, 16, 2), 32, "0", STR_PAD_LEFT);
	//vorzeichen ermitteln
	$vorz = $bin[0];
	//exponent ermitteln
	$expo = bindec(substr($bin, 1, 8)) - 127;
	//mantisse ermitteln
	$mant = (2 << 22) + bindec(substr($bin, 9, 23));
	//Zahl berechnen
	$dec = $mant * pow(2, $expo - 23) * ($vorz ? -1 : 1);


   SetValueFloat($variable,$dec);

  
   $adresszaehler=$adresszaehler+8;

}



?>

Das Skript zum Schreiben:

<?

//UDP-Socket ID
$sID=12345;

//Variablenlistenerkennung COB-ID
$cobID=2;



//Erstelle das Array für Header
$arr = array_fill(1, 39, '0');
//Erstelle Variablen, Headerlänge beträgt 20 Bytes
$Items=0;
$Length=20;


//Im Folgenden müssen alle Variablen der Variablenliste (Codesys) in der Richtigen Reihenfolge abgefragt werden!
//Dazu einfach die Funktionen readInt und readBool nacheinander aufrufen
//Die Richtige Reihenfolge und Anzahl ist wichtig!!

//readBool(12345 ,$arr,$Length,$Items);
//readInt(12345 ,$arr,$Length,$Items);
//readFloat(12345 ,$arr,$Length,$Items);




//Schreibe COB-ID, Die Anzahl der Elemente und die Größe (Anzahl Bytes),Setze Sende Zähler auf 1
$arr[18]=dechex($cobID);
$arr[26]=dechex($Items);
$arr[29]=dechex($Length);
$arr[33]=dechex(1);
//Schreibe die Identität (-3s) "Codesys spezifisch"
$arr[3]="2"; $arr[4]="d"; $arr[5]="5"; $arr[6]="3";$arr[7]="3"; $arr[8]="3";

//Array zu einer Variable verbinden
$hex=implode("",$arr);



//In Binärdaten Umwandeln
$data = hex2bin($hex);

//Daten senden
USCK_SendText($sID,$data);


function readBool($variable,&$daten,&$Laenge,&$Anzahl){
	//Variable Lesen und Umwandeln
	$value=dechex(GetValueBoolean($variable));
	//Die Daten werden an das Array angefügt
	array_push($daten, "0");
	array_push($daten, $value);
	$Laenge=$Laenge+1;
	$Anzahl=$Anzahl+1;

}

function readInt($variable,&$daten,&$Laenge,&$Anzahl){
	//Variable Lesen und Umwandeln
	$value=GetValueInteger($variable);
	$hexval=dechex($value);

	//low-,high-Byte Tausch.Die Daten werden im  an das Array angefügt
	//Für Negative Zahlen
	if($value<0){
	$value=65536+$value;
	$hexval=dechex($value);
	$split = str_split($hexval, 1);
	array_push($daten, $split[2]);array_push($daten, $split[3]);array_push($daten, $split[0]);array_push($daten, $split[1]);
	}

	//Für Positive Zahlen
	elseif ($value < 16){
	array_push($daten, "0");array_push($daten, $hexval);array_push($daten, "00");
	}
	elseif ($value < 256){
	array_push($daten, $hexval);array_push($daten, "00");
	}
	elseif ($value < 4096){
	$split = str_split($hexval, 1);
	array_push($daten, $split[1]);array_push($daten, $split[2]);array_push($daten, "0");array_push($daten, $split[0]);
	}
	else  {
	$split = str_split($hexval, 1);
	array_push($daten, $split[2]);array_push($daten, $split[3]);array_push($daten, $split[0]);array_push($daten, $split[1]);
	}
	
	
	//Werte für UDP Header Hochzählen
	$Laenge=$Laenge+2;
	$Anzahl=$Anzahl+1;
}





function readFloat($variable,&$daten,&$Laenge,&$Anzahl){
	//Variable lesen
	$value=GetValueFloat($variable);
   
   //Variable in float umwandeln
	$val_a = pack("f", $value);
	$hexval = "";
	//Variable in Hex Wandeln
	for($i = 0; $i < strlen($val_a); $i++) {
	$val_b = ord($val_a{$i});
	$hexval .= sprintf("%02X", $val_b);
	}
   //Daten an das Sende-Array Anfügen
	array_push($daten, $hexval);

   //Werte für UDP Header Hochzählen
	$Laenge=$Laenge+4;
	$Anzahl=$Anzahl+1;
}


?>

cl1x