Implement and test various functionalities of the F4/S
This commit is contained in:
parent
035475bbd0
commit
ebcb560ef4
@ -1,88 +1,206 @@
|
|||||||
using Modbus.Device; // NModbus namespace
|
using Modbus.Device; // NModbus namespace
|
||||||
using System.Net.Sockets;
|
using System.IO.Ports;
|
||||||
|
using static System.Console;
|
||||||
|
|
||||||
internal class Program
|
internal class Program
|
||||||
{
|
{
|
||||||
|
// Registers
|
||||||
|
private const ushort READINPUT1 = 100;
|
||||||
|
private const ushort INPUT1ERROR = 101;
|
||||||
|
private const ushort ALARM1STATUS = 102;
|
||||||
|
private const ushort ALARM2STATUS = 106;
|
||||||
|
private const ushort ANALOGINPUT1DECIMAL = 606;
|
||||||
|
private const ushort POWEROUTPUT1A = 103;
|
||||||
|
private const ushort SETPOINT1 = 300;
|
||||||
|
private const ushort CURRENTDAY = 1920;
|
||||||
|
private const ushort CURRENTMONTH = 1919;
|
||||||
|
private const ushort CURRENTYEAR = 1921;
|
||||||
|
private const ushort CURRENTHOUR = 1916;
|
||||||
|
private const ushort CURRENTMINUTE = 1917;
|
||||||
|
private const ushort CURRENTSECOND = 1918;
|
||||||
|
private const ushort OUTPUT1AFUNCTION = 700;
|
||||||
|
private const ushort OUTPUT1ACYCLETIMETYPE = 509;
|
||||||
|
private const ushort OUTPUT1ACYCLETIME = 506;
|
||||||
|
private const ushort DIGITALINPUT1FUNCTION = 1060;
|
||||||
|
private const ushort DIGITALINPUT1CONDITION = 1061;
|
||||||
|
private const ushort DIGITALINPUT1STATUS = 201;
|
||||||
|
private const ushort POWEROUTACTION = 1206;
|
||||||
|
private const ushort POWEROUTTIME = 1213;
|
||||||
|
private const ushort ANALOGINPUTUNITS = 608;
|
||||||
|
private const ushort CONTROLOUTPUTTYPE = 701;
|
||||||
|
private const ushort ANALOGINPUT1SENSORTYPE = 601;
|
||||||
|
private const ushort ANALOGINPUT1SENSOR = 600;
|
||||||
|
private const ushort ANALOGINPUT1SETPOINTHIGHLIMIT = 603;
|
||||||
|
private const ushort ANALOGINPUT1SETPOINTLOWLIMIT = 602;
|
||||||
|
private const ushort TEMPSCALEDISPLAY = 1923;
|
||||||
|
private const ushort TEMPSCALE = 901;
|
||||||
|
private const ushort ANALOGOUTPUT1ATYPE = 701;
|
||||||
|
private const ushort PROPORTIONALBAND = 500;
|
||||||
|
|
||||||
// Configuration
|
// Configuration
|
||||||
private const string hostname = "127.0.0.1"; // Replace with your Watlow F4 IP
|
private const byte slaveID = 1;
|
||||||
|
|
||||||
private const int port = 502;
|
|
||||||
private const byte slaveId = 0;
|
|
||||||
|
|
||||||
// Register 100 should be the first read-only input on the F4
|
|
||||||
// Value 99 or 100 should work depending on zero indexing
|
|
||||||
private const ushort loadRegister = 99;
|
|
||||||
|
|
||||||
private static void Main(string[] args)
|
private static void Main(string[] args)
|
||||||
{
|
{
|
||||||
TcpClient tcpClient = null;
|
ushort[] registers;
|
||||||
ModbusIpMaster master = null;
|
|
||||||
|
|
||||||
|
// Initialize the F4
|
||||||
|
SerialPort serialPort = (SerialPort)InitializeModbusSerialPort();
|
||||||
|
ModbusSerialMaster master = (ModbusSerialMaster)InitializeModbusMaster(serialPort);
|
||||||
|
|
||||||
|
// Then, run it
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Initialize connection
|
|
||||||
tcpClient = new TcpClient(hostname, port);
|
|
||||||
master = ModbusIpMaster.CreateIp(tcpClient);
|
|
||||||
|
|
||||||
// Monitor continuously
|
// Monitor continuously
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
// Check for Escape key press
|
// Check for escape key press
|
||||||
if (Console.KeyAvailable)
|
if (KeyAvailable)
|
||||||
{
|
{
|
||||||
ConsoleKeyInfo key = Console.ReadKey(true);
|
ConsoleKeyInfo key = ReadKey(true);
|
||||||
if (key.Key == ConsoleKey.Escape)
|
if (key.Key == ConsoleKey.Escape)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Escape pressed. Exiting...");
|
WriteLine("<ESC> pressed. Exiting...");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Display current process values
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Read load value (holding register)
|
registers = master.ReadInputRegisters(slaveID, INPUT1ERROR, 1);
|
||||||
ushort[] registers = master.ReadHoldingRegisters(slaveId, loadRegister, 1);
|
if (registers[0] != 0)
|
||||||
int load = registers[0];
|
{
|
||||||
|
WriteLine("Failure in the temperature input channel; program ends here...\n");
|
||||||
// Display load info
|
return;
|
||||||
DisplayLoadInfo(load);
|
};
|
||||||
|
registers = master.ReadInputRegisters(slaveID, READINPUT1, 1);
|
||||||
|
Write("temperature is {0:F1}; ", registers[0] / 10.0);
|
||||||
|
registers = master.ReadInputRegisters(slaveID, POWEROUTPUT1A, 1);
|
||||||
|
Write("power output is {0:F2}%\n", registers[0] / 100.0);
|
||||||
// Pause before next read
|
// Pause before next read
|
||||||
Thread.Sleep(1000);
|
Thread.Sleep(750);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Error: {ex.Message}");
|
WriteLine($"Error: {ex.Message}");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Initialization error: {ex.Message}");
|
WriteLine($"Initialization error: {ex.Message}");
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
// Shut off the output
|
||||||
|
master?.WriteSingleRegister(slaveID, SETPOINT1, 0);
|
||||||
|
|
||||||
// Clean up
|
// Clean up
|
||||||
master?.Dispose();
|
master?.Dispose();
|
||||||
tcpClient?.Close();
|
serialPort?.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
static object InitializeModbusSerialPort()
|
||||||
|
{
|
||||||
|
SerialPort serialPort;
|
||||||
|
|
||||||
|
serialPort = new SerialPort
|
||||||
|
{
|
||||||
|
PortName = "COM1",
|
||||||
|
BaudRate = 19200,
|
||||||
|
DataBits = 8,
|
||||||
|
Parity = Parity.None,
|
||||||
|
StopBits = StopBits.One,
|
||||||
|
ReadTimeout = 1000
|
||||||
|
};
|
||||||
|
serialPort.Open();
|
||||||
|
return serialPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
static object InitializeModbusMaster(SerialPort serialPort)
|
||||||
|
{
|
||||||
|
ushort[] registers;
|
||||||
|
ushort setPoint = 1000;
|
||||||
|
ModbusSerialMaster master;
|
||||||
|
DateTime dateTime;
|
||||||
|
|
||||||
|
master = ModbusSerialMaster.CreateRtu(serialPort);
|
||||||
|
|
||||||
|
// Set sensor type
|
||||||
|
WriteLine("Set sensor type to 100 Ω DIN platinum RTD");
|
||||||
|
master.WriteSingleRegister(slaveID, ANALOGINPUT1SENSOR, 1);
|
||||||
|
master.WriteSingleRegister(slaveID, ANALOGINPUT1SENSORTYPE, 11);
|
||||||
|
|
||||||
|
// Set to one decimal place (this cannot be the first initialization instruction)
|
||||||
|
WriteLine("Set to one decimal place on display");
|
||||||
|
master.WriteSingleRegister(slaveID, ANALOGINPUT1DECIMAL, 1);
|
||||||
|
|
||||||
|
// Display current setpoint high and low limits
|
||||||
|
registers = master.ReadInputRegisters(slaveID, ANALOGINPUT1SETPOINTLOWLIMIT, 1);
|
||||||
|
WriteLine("Setpoint low limit is {0}", registers[0]);
|
||||||
|
registers = master.ReadInputRegisters(slaveID, ANALOGINPUT1SETPOINTHIGHLIMIT, 1);
|
||||||
|
WriteLine("Setpoint high limit is {0}", registers[0]);
|
||||||
|
|
||||||
|
// Set to proportional mode
|
||||||
|
WriteLine("Make proportional band 5°F");
|
||||||
|
master.WriteSingleRegister(slaveID, PROPORTIONALBAND, 5);
|
||||||
|
|
||||||
|
// Set output function to heating
|
||||||
|
WriteLine("Output function is heating");
|
||||||
|
master.WriteSingleRegister(slaveID, OUTPUT1AFUNCTION, 1);
|
||||||
|
|
||||||
|
// Set analog output1 to 4-20 ma
|
||||||
|
WriteLine("Set the analog output to 4-20 MA");
|
||||||
|
master.WriteSingleRegister(slaveID, ANALOGOUTPUT1ATYPE, 0);
|
||||||
|
|
||||||
|
// Set analog input parameter to temperature
|
||||||
|
master.WriteSingleRegister(slaveID, ANALOGINPUTUNITS, 0);
|
||||||
|
|
||||||
|
// Set temperature SCALE to ON
|
||||||
|
master.WriteSingleRegister(slaveID, TEMPSCALEDISPLAY, 1);
|
||||||
|
|
||||||
|
// Set temperature scale type to Fahrenheit
|
||||||
|
master.WriteSingleRegister(slaveID, TEMPSCALE, 0);
|
||||||
|
|
||||||
|
// Set power failure response
|
||||||
|
master.WriteSingleRegister(slaveID, POWEROUTACTION, 2);
|
||||||
|
|
||||||
|
// Set output1 cycle time type to variable burst
|
||||||
|
master.WriteSingleRegister(slaveID, OUTPUT1ACYCLETIMETYPE, 0);
|
||||||
|
|
||||||
|
// Read current output1 cycle time
|
||||||
|
registers = master.ReadInputRegisters(slaveID, OUTPUT1ACYCLETIME, 1);
|
||||||
|
WriteLine("Output cycle time is {0}", registers[0]);
|
||||||
|
|
||||||
|
// Set output1 cycle time to new value
|
||||||
|
master.WriteSingleRegister(slaveID, OUTPUT1ACYCLETIME, 500);
|
||||||
|
|
||||||
|
// Check new value
|
||||||
|
registers = master.ReadInputRegisters(slaveID, OUTPUT1ACYCLETIME, 1);
|
||||||
|
WriteLine("Output cycle time is now {0}", registers[0]);
|
||||||
|
|
||||||
|
// Write setpoint to F4
|
||||||
|
WriteLine("Setting the process variable setpoint");
|
||||||
|
master.WriteSingleRegister(slaveID, SETPOINT1, setPoint);
|
||||||
|
|
||||||
|
// Verify setpoint value
|
||||||
|
WriteLine("Verifying the setpoint value");
|
||||||
|
registers = master.ReadInputRegisters(slaveID, SETPOINT1, 1);
|
||||||
|
WriteLine("Setpoint is {0:F1}", registers[0] / 10.0);
|
||||||
|
|
||||||
|
// Set F4 clock to current date and time
|
||||||
|
dateTime = DateTime.Now;
|
||||||
|
master.WriteSingleRegister(slaveID, CURRENTDAY, (ushort)dateTime.Day);
|
||||||
|
master.WriteSingleRegister(slaveID, CURRENTMONTH, (ushort)dateTime.Month);
|
||||||
|
master.WriteSingleRegister(slaveID, CURRENTYEAR, (ushort)dateTime.Year);
|
||||||
|
master.WriteSingleRegister(slaveID, CURRENTHOUR, (ushort)dateTime.Hour);
|
||||||
|
master.WriteSingleRegister(slaveID, CURRENTMINUTE, (ushort)dateTime.Minute);
|
||||||
|
master.WriteSingleRegister(slaveID, CURRENTSECOND, (ushort)dateTime.Second);
|
||||||
|
WriteLine("Set F4 clock to {0} {1}", dateTime.ToLongTimeString(), dateTime.ToLongDateString());
|
||||||
|
|
||||||
|
return master;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DisplayLoadInfo(int load)
|
|
||||||
{
|
|
||||||
Console.Clear(); // Clears the console
|
|
||||||
|
|
||||||
// Assume load is 0-65535 for 0.00-100.00% (16-bit range)
|
|
||||||
int percent = (int)load / 65535 * 100;
|
|
||||||
int barLength = (int)(percent / 2); // Scale to 50 chars for console
|
|
||||||
|
|
||||||
Console.WriteLine($"Load Value: {load}");
|
|
||||||
Console.WriteLine($"Load Percentage: {percent:F2}%");
|
|
||||||
Console.Write("Bar Graph: [");
|
|
||||||
Console.Write(new string('=', barLength));
|
|
||||||
Console.Write(new string(' ', 50 - barLength));
|
|
||||||
Console.WriteLine("]");
|
|
||||||
Console.WriteLine("\nHold ESC to exit.");
|
|
||||||
}
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user