Implement and test various functionalities of the F4/S

This commit is contained in:
mharb 2025-06-29 18:55:22 -04:00
parent 035475bbd0
commit ebcb560ef4

View File

@ -1,88 +1,206 @@
using Modbus.Device; // NModbus namespace
using System.Net.Sockets;
internal class Program
{
// Configuration
private const string hostname = "127.0.0.1"; // Replace with your Watlow F4 IP
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)
{
TcpClient tcpClient = null;
ModbusIpMaster master = null;
try
{
// Initialize connection
tcpClient = new TcpClient(hostname, port);
master = ModbusIpMaster.CreateIp(tcpClient);
// Monitor continuously
while (true)
{
// Check for Escape key press
if (Console.KeyAvailable)
{
ConsoleKeyInfo key = Console.ReadKey(true);
if (key.Key == ConsoleKey.Escape)
{
Console.WriteLine("Escape pressed. Exiting...");
break;
}
}
try
{
// Read load value (holding register)
ushort[] registers = master.ReadHoldingRegisters(slaveId, loadRegister, 1);
int load = registers[0];
// Display load info
DisplayLoadInfo(load);
// Pause before next read
Thread.Sleep(1000);
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
break;
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Initialization error: {ex.Message}");
}
finally
{
// Clean up
master?.Dispose();
tcpClient?.Close();
}
}
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.");
}
using Modbus.Device; // NModbus namespace
using System.IO.Ports;
using static System.Console;
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
private const byte slaveID = 1;
private static void Main(string[] args)
{
ushort[] registers;
// Initialize the F4
SerialPort serialPort = (SerialPort)InitializeModbusSerialPort();
ModbusSerialMaster master = (ModbusSerialMaster)InitializeModbusMaster(serialPort);
// Then, run it
try
{
// Monitor continuously
while (true)
{
// Check for escape key press
if (KeyAvailable)
{
ConsoleKeyInfo key = ReadKey(true);
if (key.Key == ConsoleKey.Escape)
{
WriteLine("<ESC> pressed. Exiting...");
break;
}
}
// Display current process values
try
{
registers = master.ReadInputRegisters(slaveID, INPUT1ERROR, 1);
if (registers[0] != 0)
{
WriteLine("Failure in the temperature input channel; program ends here...\n");
return;
};
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
Thread.Sleep(750);
}
catch (Exception ex)
{
WriteLine($"Error: {ex.Message}");
break;
}
}
}
catch (Exception ex)
{
WriteLine($"Initialization error: {ex.Message}");
}
finally
{
// Shut off the output
master?.WriteSingleRegister(slaveID, SETPOINT1, 0);
// Clean up
master?.Dispose();
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;
}
}
}