RS485 Modbus RTU relay board with PowerShell
Serial comunication with a 4 Channel RS485 Modbus RTU relay board via a universal USB – RS485 dongle using PowerShell.
Relevant links:
Write-Host "Available ports:" ([System.IO.Ports.SerialPort]::getportnames());
$COM = "COM4";
$SLAVE_ID = 0x03;
# Append 2 byte MODBUS-16 CRC to binary data array
function CRC([byte[]] $data) {
$dataCopy = @();
$dataCopy += $data;
$crcFull = 0xFFFF;
for ($i = 0; $i -lt $dataCopy.Count; $i++) {
$crcFull = ($crcFull -bxor $dataCopy[$i]) -band 0xFFFF;
for ($j = 0; $j -lt 8; $j++) {
$crclsb = ($crcFull -band 0x0001);
$crcFull = (($crcFull -shr 1) -band 0x7FFF);
if ($crclsb -eq 1) {
$crcFull = ($crcFull -bxor 0xA001) -band 0xFFFF;
}
}
}
$dataCopy += [byte] ($crcFull -band 0xFF);
$dataCopy += [byte] (($crcFull -shr 8) -band 0xFF);
return $dataCopy;
}
function RelayChannel([int] $ch) {
# Fixed serial port settings: this limits the board usage in a RS485 chain
$port = New-Object System.IO.Ports.SerialPort $COM, 9600, None, 8, one;
$DataReceivedHandler = {
param([object] $sender, [System.IO.Ports.SerialDataReceivedEventArgs] $e);
[System.IO.Ports.SerialPort] $sp = [System.IO.Ports.SerialPort] $sender;
for ($i = 1; $i -le $sp.BytesToRead; $i++) {
Write-Host (($sp.ReadByte()) | ForEach-Object ToString X2);
}
}
$null = Register-ObjectEvent -InputObject $port -EventName "DataReceived" -Action $DataReceivedHandler -MessageData $port -SourceIdentifier "SerialPort.DataReceived";
$port.Open();
# Close all channels
for ($i = 1; $i -le 4; $i++) {
$data = [byte[]] (CRC(($SLAVE_ID,0x06,0x00,$i,0x02,0x00))); # CLOSE = 0x02;
$port.Write($data, 0, $data.Count);
Start-Sleep -Milliseconds 50;
}
# Open requested channel, if channel is out of renge do nothing
if ($ch -ge 1 -and $ch -le 4) {
$data = [byte[]] (CRC(($SLAVE_ID,0x06,0x00,$ch,0x01,0x00))); # OPEN = 0x01;
$port.Write($data, 0, $data.Count);
}
$port.Close();
Unregister-Event -SourceIdentifier "SerialPort.DataReceived";
}
# Switch to channel 3
RelayChannel 3
Last update 2019-03-13 17:06