HS485-Bussystem

Hallo Forum,

Ich habe mich die letzen 4 Wochen mit dem System mal sogut es mit meinen Kentnissen geht auseinander gesetzt und auch was brauchbares hinbekommen. So ganz ohne aktive Hilfe von HJH, wäre ich noch lange nicht soweit.
Anzumerken wäre noch, das dass ganze im Moment nur mit dem HS485 Schalter-Modul funktioniert. Es erfolgt noch keine Abfrage der Checksumme beim Empfang.
(Mittlerweile integriert). Das Schaltmodul kann von überallaus angesteuert werden(Desinger usw.), es erfolgt eine Auswertung sowie eine Rückmeldung des Schaltzustandes in IPS.

Im Script HS485_Schalter sind nur die Comport ID und die Moduladresse anzupassen. Dieses ist auch dokumentiert.
Im Empfangsscript das selbe, wobei hier die Daten im Dezimalen Zahlenbereich vorliegen. Das Script ist noch nicht fertig, da es für alle Bausteine benutzt wird, die ich selbst verwende.
Diese sind HS485S, HS485-IO127, HS485-LX1 und Temp-Feuchtesensor JCU 10 SI.
Variablen zum selbst anlegen, Aktoren, Datenempfang und zum schalten.
Zum Datenempfang, Comport und Registervariable einrichten.
Comport nach Vorgabe 19200,8,1,Even. Registervariable Append Variable und 8096 Bytes.
Wird der HS485-Schalter mit Schalter oder Stromstoßschalter angesteuert, ist darauf zuachten, das die Togglebits in der Software nicht gesetzt sind. Bei Taster oder Stromstoßrelais ist es egal.

Für Feedback und Anregungen bitte hier antworten.

Da die ganze Auswerterei nicht so ohne ist, beschränke ich mich auf das nötigste was zum Senden/Empfangen und Schalten über IPS nötig ist.

Das Script für den Schalter. Funktion, Ein,Aus, Toggle

Um eine 100 prozentige Zustandsanzeige der Variablen zuerhalten, ist das Modul nicht in einen Timerzustand über die Software zusetzen, sonder per Script über IPS. Da das Modul keinerlei Rückmeldung sendet!

Um Missverständnisse zu vermeiden, diese Scripte funktionieren mit allen Modulen. Aber nur dann, wenn sie für das entsprechende Modul auch angepasst wurden.

Übernehmen kann man nach Anpassung der Com-ID und Moduladresse direkt was hier vorgestellt wurde.

/*
*******************************
 IP-SYMCON Event Scripting
*******************************
File     : HS485_Schalter.ips.php
Trigger  : OnUpdate HS485_Schalter
*/

$ComID   = 33104;  // Comport ID muss angepasst werden
$HS485_Schalter = GetValueString("HS485_Schalter");  // Triggervariable

// Zuweisung der Sendedaten
$Startzeichen    = "\xFD";               // Startzeichen FD
$HS485_S         = "\x00\x00\x10\x98";   // Moduladresse muss angepasst werden !
$Kontrollzeichen = "\x98";               // Kontrollzeichen 98
$Absender        = "\x00\x00\x00\x00";   // Absenderadresse vom PC immer 0000
$Frame6          = "\x06";               // Framelaenge ergibt sich aus Befehl, Sensoreingang, Aktornummer, Event(Ein,Aus,Toggle) und Checksumme
$Frame4          = "\x04";
$Befehl_S        = "\x53";               // Framedaten hier Befehl "S" Abfrage Relaiszustand
$Befehl_s        = "\x73";               // Framedaten hier Befehl "s" Aktor setzen
$Sensoreingang   = "\x00";               // beim setzen und Abfragen immer 0
$HS485_S_A1      = "\x00";               // Aktor, Relais 1
$HS485_S_A2      = "\x01";               // Aktor, Relais 2
$Ein             = "\x01";               // Event Ein
$Aus             = "\x00";               // Event Aus
$Toggle          = "\xFF";               // Event Toggle
$CRC             = "\x00\x00";           // wird an Datenframe übergeben und durch berechnete Checksumme ersetzt


switch($HS485_Schalter)  // Schalten der Ausgänge des Schalters HS485 S
{
  case "S1t":  // Aktor 1 Toggle und Schaltzustand abfragen
  $SA1t = $Startzeichen.$HS485_S.$Kontrollzeichen.$Absender.$Frame6.$Befehl_s.$Sensoreingang.$HS485_S_A1.$Toggle;
  $CRC16 = GetCRC16 ($SA1t.$CRC);                  // Checksumme berechnen
  $CRC16str = chr($CRC16>>8). chr($CRC16&0xff);    // Hi-Lo-Byte der Checksumme extrahieren
  $Aktor1 = $SA1t.$CRC16str;                       // Checksumme an Datenframe übergeben
  COMPort_SendText($ComID, $Aktor1);               // Datenframe über Comport senden
  SetValueString("HS485_Schalter","");             // Variable leeren
  $ZHS485_S_A1 = $Startzeichen.$HS485_S.$Kontrollzeichen.$Absender.$Frame4.$Befehl_S.$HS485_S_A1;
  $CRC16 = GetCRC16 ($ZHS485_S_A1.$CRC);           // Checksumme berechnen
  $CRC16str = chr($CRC16>>8). chr($CRC16&0xff);    // Hi-Lo-Byte der Checksumme extrahieren
  $S_A1 = $ZHS485_S_A1.$CRC16str;                  // Checksumme an Datenframe übergeben
  COMPort_SendText($ComID, $S_A1);                 // Datenframe über Comport senden
  SetValueString("HS485_Schalter","");             // Variable leeren
  break;

  case "S1e":  // Aktor 1 Einschalten und Schaltzustand abfragen
  $SA1e = $Startzeichen.$HS485_S.$Kontrollzeichen.$Absender.$Frame6.$Befehl_s.$Sensoreingang.$HS485_S_A1.$Ein;
  $CRC16 = GetCRC16 ($SA1e.$CRC);                   // Checksumme berechnen
  $CRC16str = chr($CRC16>>8). chr($CRC16&0xff);     // Hi-Lo-Byte der Checksumme extrahieren
  $Aktor1 = $SA1e.$CRC16str;                        // Checksumme an Datenframe übergeben
  COMPort_SendText($ComID, $Aktor1);                // Datenframe über Comport senden
  SetValueString("HS485_Schalter","");              // Variable leeren
  $ZHS485_S_A1 = $Startzeichen.$HS485_S.$Kontrollzeichen.$Absender.$Frame4.$Befehl_S.$HS485_S_A1;
  $CRC16 = GetCRC16 ($ZHS485_S_A1.$CRC);            // Checksumme berechnen
  $CRC16str = chr($CRC16>>8). chr($CRC16&0xff);     // Hi-Lo-Byte der Checksumme extrahieren
  $S_A1 = $ZHS485_S_A1.$CRC16str;                   // Checksumme an Datenframe übergeben
  COMPort_SendText($ComID, $S_A1);                  // Datenframe über Comport senden
  SetValueString("HS485_Schalter","");              // Variable leeren
  break;

  case "S1a":   // Aktor 1 Ausschalten und Schaltzustand abfragen
  $SA1a = $Startzeichen.$HS485_S.$Kontrollzeichen.$Absender.$Frame6.$Befehl_s.$Sensoreingang.$HS485_S_A1.$Aus;
  $CRC16 = GetCRC16 ($SA1a.$CRC);                   // Checksumme berechnen
  $CRC16str = chr($CRC16>>8). chr($CRC16&0xff);     // Hi-Lo-Byte der Checksumme extrahieren
  $Aktor1 = $SA1a.$CRC16str;                        // Checksumme an Datenframe übergeben
  COMPort_SendText($ComID, $Aktor1);                // Datenframe über Comport senden
  SetValueString("HS485_Schalter","");              // Variable leeren
  $ZHS485_S_A1 = $Startzeichen.$HS485_S.$Kontrollzeichen.$Absender.$Frame4.$Befehl_S.$HS485_S_A1;
  $CRC16 = GetCRC16 ($ZHS485_S_A1.$CRC);            // Checksumme berechnen
  $CRC16str = chr($CRC16>>8). chr($CRC16&0xff);     // Hi-Lo-Byte der Checksumme extrahieren
  $S_A1 = $ZHS485_S_A1.$CRC16str;                   // Checksumme an Datenframe übergeben
  COMPort_SendText($ComID, $S_A1);                  // Datenframe über Comport senden
  SetValueString("HS485_Schalter","");              // Variable leeren
  break;

  case "S2t":   // Aktor 2 Toggle und Schaltzustand abfragen
  $SA2t = $Startzeichen.$HS485_S.$Kontrollzeichen.$Absender.$Frame6.$Befehl_s.$Sensoreingang.$HS485_S_A2.$Toggle;
  $CRC16 = GetCRC16 ($SA2t.$CRC);                   // Checksumme berechnen
  $CRC16str = chr($CRC16>>8). chr($CRC16&0xff);     // Hi-Lo-Byte der Checksumme extrahieren
  $Aktor2 = $SA2t.$CRC16str;                        // Checksumme an Datenframe übergeben
  COMPort_SendText($ComID, $Aktor2);                // Datenframe über Comport senden
  SetValueString("HS485_Schalter","");              // Variable leeren
  $ZHS485_S_A2 = $Startzeichen.$HS485_S.$Kontrollzeichen.$Absender.$Frame4.$Befehl_S.$HS485_S_A2;
  $CRC16 = GetCRC16 ($ZHS485_S_A2.$CRC);            // Checksumme berechnen
  $CRC16str = chr($CRC16>>8). chr($CRC16&0xff);     // Hi-Lo-Byte der Checksumme extrahieren
  $S_A2 = $ZHS485_S_A2.$CRC16str;                   // Checksumme an Datenframe übergeben
  COMPort_SendText($ComID, $S_A2);                  // Datenframe über Comport senden
  SetValueString("HS485_Schalter","");              // Variable leeren
  break;
  
  case "S2e":   // Aktor 2 Einschalten und Schaltzustand abfragen
  $SA2e = $Startzeichen.$HS485_S.$Kontrollzeichen.$Absender.$Frame6.$Befehl_s.$Sensoreingang.$HS485_S_A2.$Ein;
  $CRC16 = GetCRC16 ($SA2e.$CRC);                  // Checksumme berechnen
  $CRC16str = chr($CRC16>>8). chr($CRC16&0xff);    // Hi-Lo-Byte der Checksumme extrahieren
  $Aktor2 = $SA2e.$CRC16str;                       // Checksumme an Datenframe übergeben
  COMPort_SendText($ComID, $Aktor2);               // Datenframe über Comport senden
  SetValueString("HS485_Schalter","");             // Variable leeren
  $ZHS485_S_A2 = $Startzeichen.$HS485_S.$Kontrollzeichen.$Absender.$Frame4.$Befehl_S.$HS485_S_A2;
  $CRC16 = GetCRC16 ($ZHS485_S_A2.$CRC);           // Checksumme berechnen
  $CRC16str = chr($CRC16>>8). chr($CRC16&0xff);    // Hi-Lo-Byte der Checksumme extrahieren
  $S_A2 = $ZHS485_S_A2.$CRC16str;                  // Checksumme an Datenframe übergeben
  COMPort_SendText($ComID, $S_A2);                 // Datenframe über Comport senden
  SetValueString("HS485_Schalter","");             // Variable leeren
  break;
  
  case "S2a":   // Aktor 2 Ausschalten und Schaltzustand abfragen
  $SA2a = $Startzeichen.$HS485_S.$Kontrollzeichen.$Absender.$Frame6.$Befehl_s.$Sensoreingang.$HS485_S_A2.$Aus;
  $CRC16 = GetCRC16 ($SA2a.$CRC);                  // Checksumme berechnen
  $CRC16str = chr($CRC16>>8). chr($CRC16&0xff);    // Hi-Lo-Byte der Checksumme extrahieren
  $Aktor2 = $SA2a.$CRC16str;                       // Checksumme an Datenframe übergeben
  COMPort_SendText($ComID, $Aktor2);               // Datenframe über Comport senden
  SetValueString("HS485_Schalter","");             // Variable leeren
  $ZHS485_S_A2 = $Startzeichen.$HS485_S.$Kontrollzeichen.$Absender.$Frame4.$Befehl_S.$HS485_S_A2;
  $CRC16 = GetCRC16 ($ZHS485_S_A2.$CRC);           // Checksumme berechnen
  $CRC16str = chr($CRC16>>8). chr($CRC16&0xff);    // Hi-Lo-Byte der Checksumme extrahieren
  $S_A2 = $ZHS485_S_A2.$CRC16str;                  // Checksumme an Datenframe übergeben
  COMPort_SendText($ComID, $S_A2);                 // Datenframe über Comport senden
  SetValueString("HS485_Schalter","");             // Variable leeren
  break;
}

// Funktion zur Berechnung der Checksumme

function GetCRC16($s)
{
$CRCreg = 0xffff00;
for ($cp=0; $cp<strlen($s); $cp++)
{
  $CRCreg |= ord($s[$cp]);
  for ($bp=0; $bp<8; $bp++)
  {
   $CRCreg <<= 1;
   if ($CRCreg & 0x1000000) $CRCreg ^= 0x100200; // hier ist das Polynom 0x1002 enthalten
   $CRCreg &= 0xffffff;
  }
}
return $CRCreg >> 8;
}
<?
/*
*******************************
 IP-SYMCON Event Scripting
*******************************
File     : HS485_Datenempfang.ips.php
Trigger  : OnUpdate Hs485_Daten
Interval : 
*/
 
$ComID = 33104;                        // Comport ID
define ("STARTZEICHEN1", "\xFD");      // Startzeichen 1
define ("STARTZEICHEN2", "\xFE");      // Startzeichen 2
define ("ESCAPE",        "\xFC");      // ESCAPE-Zeichen
define ("MAXZEIT",            2);      // maximale Wartezeit in Sekunden
 
$stopzeit = time() + MAXZEIT;
do
{
 $datenstrom = GetValueString("HS485_Daten");
 $startzeichengefunden = false;
 $CRC16 = 1;
 $daten = "";
 $laenge = strlen($datenstrom);
 for ($i=0; $i<$laenge and $CRC16!=0; $i++)
 {
  $chr = $datenstrom[$i];                   // Zeichen einlesen
  if (!$startzeichengefunden)               // STARTZEICHEN schon gefunden?
  {
   if (($chr == STARTZEICHEN1) or ($chr == STARTZEICHEN2)) // nein, daher suchen nach STARTZEICHEN
   {
    $startzeichengefunden = true;           // STARTZEICHEN gefunden
    $daten = $chr;
   }
   continue;                                // STARTZEICHEN immer noch nicht gefunden
  }
 
  if ($chr == ESCAPE)                       // falls ESCAPE gefunden wurde
  {
   $i++;                                    // ESCAPE verwerfen
   $chr = chr(ord($datenstrom[$i]) + 0x80); // und nachfolgendes Zeichen korrigieren
  }
 
  $daten .= $chr;                           // ab hier Checksumme suchen
  $CRC16 = GetCRC16($daten);
 }
} while (($CRC16 != 0) and ($stopzeit > time()));
 
if ($CRC16 != 0)
 return "ungültige Daten!";            // keine gültigen Daten innerhalb von MAXZEIT empfangen
else
 SetValueString("HS485_Daten", "");    // Daten gültig, Puffer kann gelöscht werden
 
 
// Daten aus empfangenem String extrahieren, Zuweisung der einzelnen Bytes
$Startzeichen    = String2Value($daten,0,1);
$KontrollByte    = String2Value($daten,5,1);
$Moduladresse    = String2Value($daten,6,4);
$Moduladresse1   = 6378; //HS485_127IO
$Moduladresse2   = 4248; //HS485 _S
$Moduladresse3   = 3250; //HS485_LX1
$Moduladresse4   = 4848; //HS485_TFS Keller
$Moduladresse5   = 4826; //HS485_TFS Wohnzimmer
$Framelaenge     = String2Value($daten,10,1);
$Frame4          = 4;
$Frame5          = 5;
$Frame6          = 6;
$Datenframe1     = String2Value($daten,11,1);
$KeyEvent        = 75;
$Datenframe2     = String2Value($daten,12,1);
$Datenframe3     = String2Value($daten,13,1);
$Datenframe4     = String2Value($daten,14,1);
$Datenframe5     = String2Value($daten,15,1);
$Datenframe6     = String2Value($daten,16,1);
$Datenframe7     = String2Value($daten,17,1);
$HS485_127IO_A1  = 12;  // 127IO Relais 1
$HS485_127IO_A2  = 13;  // 127IO Relais 2
$HS485_127IO_A3  = 14;  // 127IO Relais 3
$HS485_127IO_A4  = 15;  // 127IO Relais 4
$HS485_127IO_A5  = 16;  // 127IO Relais 5
$HS485_127IO_A6  = 17;  // 127IO Relais 6
$HS485_127IO_A7  = 18;  // 127IO Relais 7
$HS485_S_A1      = 0;   // S     Relais 1
$HS485_S_A2      = 1;   // S     Relais 2
$Ein             = 1;   // Event Ein
$Aus             = 0;   // Event Aus
$Toggle          = 255; // Event toggle
//$CRC           = "\x00\x00";
 
// Rückmeldung Schaltzustand der Aktoren
$Schaltzustand = $Startzeichen.$Moduladresse.$Frame4.$Datenframe1.$Datenframe2;
  if ($Schaltzustand == $Startzeichen.$Moduladresse2.$Frame4.$HS485_S_A1.$Aus)
  {
   SetValueBoolean("HS485S_Aktor1", false);
  }
  if ($Schaltzustand == $Startzeichen.$Moduladresse2.$Frame4.$HS485_S_A1.$Ein)
  {
   SetValueBoolean("HS485S_Aktor1", true);
  }
  if ($Schaltzustand == $Startzeichen.$Moduladresse2.$Frame4.$HS485_S_A2.$Aus)
  {
   SetValueBoolean("HS485S_Aktor2", false);
  }
  if ($Schaltzustand == $Startzeichen.$Moduladresse2.$Frame4.$HS485_S_A2.$Ein)
  {
   SetValueBoolean("HS485S_Aktor2", true);
  }
 
// Rückmeldung des Schaltzustandes HS485_S nach Taster/Schalterbetätigung
$SchaltzustandModul = $Startzeichen.$Moduladresse.$Frame6.$Datenframe1.$Datenframe2;
  if ($SchaltzustandModul == $Startzeichen.$Moduladresse2.$Frame6.$KeyEvent.$HS485_S_A1)
  {
   $S1 = "\xFD\x00\x00\x10\x98\x98\x00\x00\x00\x00\x04\x53\x00";
   $ZHS485_S_A1 = $S1;
   $CRC16 = GetCRC16 ($ZHS485_S_A1."\x00\x00");     // Checksumme berechnen
   $CRC16str = chr($CRC16>>8). chr($CRC16&0xff);    // Hi-Lo-Byte der Checksumme extrahieren
   $S_A1 = $ZHS485_S_A1.$CRC16str;                  // Checksumme an Datenframe übergeben
   COMPort_SendText($ComID, $S_A1);                 // Datenframe über Comport senden
  }
  if ($SchaltzustandModul == $Startzeichen.$Moduladresse2.$Frame6.$KeyEvent.$HS485_S_A2)
  {
   $S2 = "\xFD\x00\x00\x10\x98\x98\x00\x00\x00\x00\x04\x53\x01";
   $ZHS485_S_A2 = $S2;
   $CRC16 = GetCRC16 ($ZHS485_S_A2."\x00\x00");     // Checksumme berechnen
   $CRC16str = chr($CRC16>>8). chr($CRC16&0xff);    // Hi-Lo-Byte der Checksumme extrahieren
   $S_A2 = $ZHS485_S_A2.$CRC16str;                  // Checksumme an Datenframe übergeben
   COMPort_SendText($ComID, $S_A2);                 // Datenframe über Comport senden
  }
 
// Auswertung Helligkeitssensor LX1. Bereich von 0-200000 Lux
$Helligkeit = 0;
$LX1 = $Startzeichen.$KontrollByte.$Moduladresse.$Framelaenge;
 if($LX1 == $Startzeichen.$KontrollByte.$Moduladresse3.$Frame6)
  {
   $Helligkeit += $Datenframe1;
   $Helligkeit <<= 8;
   $Helligkeit += $Datenframe2;
   $Helligkeit <<= 8;
   $Helligkeit += $Datenframe3;
   $Helligkeit <<= 8;
   $Helligkeit += $Datenframe4;
   SetValueInteger("HS485_Luxsensor", $Helligkeit);
  }
 
// Auswertung Temperatur-Feuchtesensor JCU10_TFS. Bereich von 0-65°C und 0-100%
$Temp    = 0;
$Feuchte = 0;
$TFS = $Startzeichen.$KontrollByte.$Moduladresse.$Framelaenge;
 if($TFS == $Startzeichen.$KontrollByte.$Moduladresse4.$Frame5)
 {
  $Temp += $Datenframe1;
  $Temp <<= 8;
  $Temp |= $Datenframe2;
  $Temp = (float)$Temp/10;
  $Feuchte  = $Datenframe3;
  SetValueFloat("TFS_Temperatur", $Temp);
  SetValueInteger("TFS_Feuchte", $Feuchte);
 }
 
// Funktion zur Checksummenberechnung
function GetCRC16($s)
{
$CRCreg = 0xffff00;
for ($cp=0; $cp<strlen($s); $cp++)
{
  $CRCreg |= ord($s[$cp]);
  for ($bp=0; $bp<8; $bp++)
  {
   $CRCreg <<= 1;
   if ($CRCreg & 0x1000000) $CRCreg ^= 0x100200; // hier ist das Polynom 0x1002 enthalten
   $CRCreg &= 0xffffff;
  }
}
return $CRCreg >> 8;
}
 
// Funktion zur Umwandlung eines Teil eines String in eine Zahl, Zählung beginnt bei Null
function String2Value($str, $p, $c) // String, Position, Anzahl Characters
{
 $val = 0;
 for ($i=0; $i<$c; $i++)
 {
  $val <<= 8;
  $val += ord($str[$p+$i]);
 }
 return $val; // Rückgabe: Zahl
}
 
// Funktion zur Umwandlung eines String nach Hex
function Str2Hex($daten)
{
 $Hex = "";
 for($i=0; $i<strlen($daten); $i++)
   $Hex .= sprintf("%02X ", ord($daten[$i]));
 return $Hex; // String in hexadezimaler Schreibweise
}
$daten = Str2Hex($daten);
IPS_LogMessage($IPS_SELF,"HS485_Daten:  ". $daten);
?>

Auslesen der Daten Helligkeitssensor sowie Temp/Feuchtemodul

// Rückmeldung des Schaltzustandes HS485_S nach Taster/Schalterbetätigung
korrigiert, Beschreibung nicht stimmig.
Danke Jens.

Abfrage der Helligkeit.

/*
*******************************
 IP-SYMCON Event Scripting
*******************************
File     : HS485_LX1.ips.php
Trigger  : 
Interval : nach belieben
*/



$ComID = 33104;                                // Comport_ID muss angepasst werden

// Zuweisung der Sendedaten
$Startzeichen    = "\xFD";                     // Startzeichen FD Vorgabe
$HS485_LX1       = "\x00\x00\x0C\xB2";         // Moduladresse muss angepasst werden
$Kontrollzeichen = "\x98";                     // Kontrollzeichen 98 Vorgabe
$Absender        = "\x00\x00\x00\x00";         // Absenderadresse vom PC immer 0000
$Framelaenge     = "\x03";                     // Framelaenge ergibt sich aus Befehl und Checksumme
$Befehl          = "\x4C";                     // Befehl "L" zum abfragen der Helligkeit
$CRC             = "\x00\x00";                 // wird an Datenframe übergeben und durch berechnete Checksumme ersetzt

// Abfragen des Sensors
$LX1 = $Startzeichen.$HS485_LX1.$Kontrollzeichen.$Absender.$Framelaenge.$Befehl;  // Datenframe
$CRC16 = GetCRC16 ($LX1.$CRC);                   // Checksumme berechnen
$CRC16str = chr($CRC16>>8). chr($CRC16&0xff);    // Hi-Lo-Byte der Checksumme extrahieren
$LX1 = $LX1.$CRC16str;                           // Checksumme an Datenframe übergeben
COMPort_SendText($ComID, $LX1);                  // Datenframe über Comport senden
SetValueString("HS485_Ausgang","");              // Varaible leeren


// Funktion zur Berechnung der Checksumme
function GetCRC16($s)
{
$CRCreg = 0xffff00;
for ($cp=0; $cp<strlen($s); $cp++)
{
  $CRCreg |= ord($s[$cp]);
  for ($bp=0; $bp<8; $bp++)
  {
   $CRCreg <<= 1;
   if ($CRCreg & 0x1000000) $CRCreg ^= 0x100200; // hier ist das Polynom 0x1002 enthalten
   $CRCreg &= 0xffffff;
  }
}
return $CRCreg >> 8;
}

Abfrage der Temperatur/Feuchte

/*
*******************************
 IP-SYMCON Event Scripting
*******************************
File     : HS485_TFS.ips.php
Trigger  : 
Interval : nach belieben
*/


$ComID = 33104;                                // Comport_ID muss angepasst werden

// Zuweisung der Sendedaten
$Startzeichen    = "\xFD";                     // Startzeichen FD Vorgabe
$HS485_TFS       = "\x00\x00\x06\xC0";         // Moduladresse muss angepasst werden
$Kontrollzeichen = "\x98";                     // Kontrollzeichen 98 Vorgabe
$Absender        = "\x00\x00\x00\x00";         // Absenderadresse vom PC immer 0000
$Framelaenge     = "\x03";                     // Framelaenge ergibt sich aus Befehl und Checksumme
$Befehl          = "\x46";                     // Befehl "F" zum abfragen Temp/Feuchte
$CRC             = "\x00\x00";                 // wird an Datenframe übergeben und durch berechnete Checksumme ersetzt

// Abfragen des Sensors
$TFS = $Startzeichen.$HS485_TFS.$Kontrollzeichen.$Absender.$Framelaenge.$Befehl;  // Datenframe
$CRC16 = GetCRC16 ($TFS.$CRC);                   // Checksumme berechnen
$CRC16str = chr($CRC16>>8). chr($CRC16&0xff);    // Hi-Lo-Byte der Checksumme extrahieren
$TFS = $TFS.$CRC16str;                           // Checksumme an Datenframe übergeben
COMPort_SendText($ComID, $TFS);                  // Datenframe über Comport senden
SetValueString("HS485_Ausgang","");              // Variable leeren


// Funktion zur Berechnung der Checksumme
function GetCRC16($s)
{
$CRCreg = 0xffff00;
for ($cp=0; $cp<strlen($s); $cp++)
{
  $CRCreg |= ord($s[$cp]);
  for ($bp=0; $bp<8; $bp++)
  {
   $CRCreg <<= 1;
   if ($CRCreg & 0x1000000) $CRCreg ^= 0x100200; // hier ist das Polynom 0x1002 enthalten
   $CRCreg &= 0xffffff;
  }
}
return $CRCreg >> 8;
}

Hallo,

habe das Datenempfangsscript erweitert.

Die Checksumme wird nun auch beim Datenempfang berechnet.
Desweiteren werden die Steuerzeichen im Datenstrom berücksichtigt und gegebenenfalls korrigiert.

Hier auch nochmal ein Dankeschön an HJH für seine Mithilfe.

Es wird in den nächsten Tagen eine verbesserte Checksummenberechnung in die Scripte übernommen.
Ich werde dann die Scripte anpassen und austauschen. Gegebenenfalls gibt es auch noch was neues.

HJH hat daran noch etwas geändert, sodas diese direkt verwendet werden kann.
Hierfür wieder ein Dankeschön an Hans-Jörg.

//*************************************************************** 
function CRC16a($s)           // CRC16 with augmented message 
{ 
 // die folgenden beiden Werte sind abhängig vom Anwendungszweck. 
 // Für HS485 gilt: 
 $CRCreg = 0xffff << 8;       // Startwert 
 $PLYreg = 0x1002 << 8;       // Polynom 
 $s .= "\x00\x00"; 
 $len = strlen($s); 

 for ($cp=0; $cp<$len; $cp++) 
 { 
  $CRCreg |= ord($s[$cp]); 
  for ($bp=0; $bp<8; $bp++) 
  { 
   $CRCreg <<= 1; 
   if ($CRCreg & 0x1000000) $CRCreg ^= $PLYreg; 
  } 
 } 
 return ($CRCreg >> 8) & 0xffff; 
}

Aufruf:
- Berechnung der CRC:
// ***************************************
// $crc = CRC16a($datenstring."\x00\x00"); // veraltet, nicht mehr verwenden!
$crc = CRC16a($datenstring);  // dieser Aufruf ist jetzt korrekt 



Für eine saubere Daten/Spannungsübertragung bietet sich eine getrennte Spannungsversorgung für den Wandler HS485 PCI an.

Jenach Ausbau und Zustand des USB-Anschluss(Hub) kann es zu Datenmüll auf dem Bus kommen.

Eine bis jetzt bewährte Technik, getrennte Spannungsversorgung für den Bus A-B und die Module, sowie ein separates Netzteil für den Wandler HS 485 PCI. Hierbei sollte man die vorgegebene Leistung von 15 Watt einhalten.