2025-07-05 20:22:53 -04:00
|
|
|
|
using Modbus.Device; // NModbus namespace for Modbus communication
|
|
|
|
|
using System.IO.Ports; // Namespace for serial port communication
|
|
|
|
|
using static System.Console; // Static reference to Console for easier access
|
2025-06-29 18:55:22 -04:00
|
|
|
|
|
|
|
|
|
internal class Program
|
|
|
|
|
{
|
2025-07-05 20:22:53 -04:00
|
|
|
|
// Modbus Register Addresses for various parameters
|
|
|
|
|
private static class ModbusRegisters
|
2025-06-29 18:55:22 -04:00
|
|
|
|
{
|
2025-07-05 20:22:53 -04:00
|
|
|
|
public const ushort ReadInput1 = 100; // Register for reading input 1
|
|
|
|
|
public const ushort Input1Error = 101; // Register for input 1 error status
|
|
|
|
|
public const ushort Alarm1Status = 102; // Register for alarm 1 status
|
|
|
|
|
public const ushort Alarm2Status = 106; // Register for alarm 2 status
|
|
|
|
|
public const ushort AnalogInput1Decimal = 606; // Register for analog input 1 decimal setting
|
|
|
|
|
public const ushort PowerOutput1A = 103; // Register for power output 1A
|
|
|
|
|
public const ushort SetPoint1 = 300; // Register for set point 1
|
|
|
|
|
public const ushort CurrentDay = 1920; // Register for current day
|
|
|
|
|
public const ushort CurrentMonth = 1919; // Register for current month
|
|
|
|
|
public const ushort CurrentYear = 1921; // Register for current year
|
|
|
|
|
public const ushort CurrentHour = 1916; // Register for current hour
|
|
|
|
|
public const ushort CurrentMinute = 1917; // Register for current minute
|
|
|
|
|
public const ushort CurrentSecond = 1918; // Register for current second
|
|
|
|
|
public const ushort Output1AFunction = 700; // Register for output 1A function
|
|
|
|
|
public const ushort Output1ACycleTimeType = 509; // Register for output 1A cycle time type
|
|
|
|
|
public const ushort Output1ACycleTime = 506; // Register for output 1A cycle time
|
|
|
|
|
public const ushort DigitalInput1Function = 1060; // Register for digital input 1 function
|
|
|
|
|
public const ushort DigitalInput1Condition = 1061; // Register for digital input 1 condition
|
|
|
|
|
public const ushort DigitalInput1Status = 201; // Register for digital input 1 status
|
|
|
|
|
public const ushort PowerOutAction = 1206; // Register for power output action
|
|
|
|
|
public const ushort PowerOutTime = 1213; // Register for power output time
|
|
|
|
|
public const ushort AnalogInputUnits = 608; // Register for analog input units
|
|
|
|
|
public const ushort ControlOutputType = 701; // Register for control output type
|
|
|
|
|
public const ushort AnalogInput1SensorType = 601; // Register for analog input 1 sensor type
|
|
|
|
|
public const ushort AnalogInput1Sensor = 600; // Register for analog input 1 sensor
|
|
|
|
|
public const ushort AnalogInput1SetPointHighLimit = 603; // Register for high limit of analog input 1 set point
|
|
|
|
|
public const ushort AnalogInput1SetPointLowLimit = 602; // Register for low limit of analog input 1 set point
|
|
|
|
|
public const ushort TempScaleDisplay = 1923; // Register for temperature scale display
|
|
|
|
|
public const ushort TempScale = 901; // Register for temperature scale
|
|
|
|
|
public const ushort AnalogOutput1AType = 701; // Register for analog output 1A type
|
|
|
|
|
public const ushort ProportionalBand = 500; // Register for proportional band
|
|
|
|
|
}
|
2025-06-29 18:55:22 -04:00
|
|
|
|
|
2025-07-05 20:22:53 -04:00
|
|
|
|
// Configuration for Modbus Slave ID
|
|
|
|
|
private const byte SlaveID = 1;
|
2025-06-29 18:55:22 -04:00
|
|
|
|
|
2025-07-05 20:22:53 -04:00
|
|
|
|
private static void Main(string[] args)
|
|
|
|
|
{
|
2025-06-29 18:55:22 -04:00
|
|
|
|
try
|
|
|
|
|
{
|
2025-07-05 20:22:53 -04:00
|
|
|
|
using SerialPort serialPort = InitializeSerialPort();
|
|
|
|
|
using ModbusSerialMaster master = InitializeModbusMaster(serialPort);
|
2025-06-29 18:55:22 -04:00
|
|
|
|
|
2025-07-05 20:22:53 -04:00
|
|
|
|
MonitorProcessValues(master);
|
2025-06-29 18:55:22 -04:00
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
WriteLine($"Initialization error: {ex.Message}");
|
|
|
|
|
}
|
2025-07-05 20:22:53 -04:00
|
|
|
|
}
|
2025-06-29 18:55:22 -04:00
|
|
|
|
|
2025-07-05 20:22:53 -04:00
|
|
|
|
private static void MonitorProcessValues(ModbusSerialMaster master)
|
|
|
|
|
{
|
|
|
|
|
while (true)
|
2025-06-29 18:55:22 -04:00
|
|
|
|
{
|
2025-07-05 20:22:53 -04:00
|
|
|
|
if (KeyAvailable && ReadKey(true).Key == ConsoleKey.Escape)
|
|
|
|
|
{
|
|
|
|
|
WriteLine("<ESC> pressed. Exiting...");
|
|
|
|
|
break;
|
|
|
|
|
}
|
2025-06-29 18:55:22 -04:00
|
|
|
|
|
2025-07-05 20:22:53 -04:00
|
|
|
|
try
|
2025-06-29 18:55:22 -04:00
|
|
|
|
{
|
2025-07-05 20:22:53 -04:00
|
|
|
|
if (IsInputError(master))
|
|
|
|
|
{
|
|
|
|
|
WriteLine("Failure in the temperature input channel; program ends here...\n");
|
|
|
|
|
return; // Exit if there's an error
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DisplayCurrentValues(master);
|
|
|
|
|
Thread.Sleep(750); // Wait before the next read
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
WriteLine($"Error: {ex.Message}");
|
|
|
|
|
break; // Exit on error
|
|
|
|
|
}
|
2025-06-29 18:55:22 -04:00
|
|
|
|
}
|
2025-07-05 20:22:53 -04:00
|
|
|
|
}
|
2025-06-29 18:55:22 -04:00
|
|
|
|
|
2025-07-05 20:22:53 -04:00
|
|
|
|
private static bool IsInputError(ModbusSerialMaster master)
|
|
|
|
|
{
|
|
|
|
|
ushort[] registers = master.ReadInputRegisters(SlaveID, ModbusRegisters.Input1Error, 1);
|
|
|
|
|
return registers[0] != 0; // Non-zero indicates an error
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void DisplayCurrentValues(ModbusSerialMaster master)
|
|
|
|
|
{
|
|
|
|
|
ushort[] temperatureRegisters = master.ReadInputRegisters(SlaveID, ModbusRegisters.ReadInput1, 1);
|
|
|
|
|
Write("Temperature is {0:F1}; ", temperatureRegisters[0] / 10.0); // Convert to proper format
|
|
|
|
|
|
|
|
|
|
ushort[] powerOutputRegisters = master.ReadInputRegisters(SlaveID, ModbusRegisters.PowerOutput1A, 1);
|
|
|
|
|
WriteLine("Power output is {0:F2}%", powerOutputRegisters[0] / 100.0); // Convert to percentage
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static SerialPort InitializeSerialPort()
|
|
|
|
|
{
|
|
|
|
|
SerialPort serialPort = new SerialPort
|
2025-06-29 18:55:22 -04:00
|
|
|
|
{
|
2025-07-05 20:22:53 -04:00
|
|
|
|
PortName = "COM1", // Set the COM port
|
|
|
|
|
BaudRate = 19200, // Set the baud rate
|
|
|
|
|
DataBits = 8, // Set data bits
|
|
|
|
|
Parity = Parity.None, // Set parity
|
|
|
|
|
StopBits = StopBits.One, // Set stop bits
|
|
|
|
|
ReadTimeout = 1000 // Set read timeout
|
|
|
|
|
};
|
|
|
|
|
serialPort.Open(); // Open the serial port
|
|
|
|
|
return serialPort; // Return the configured serial port
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static ModbusSerialMaster InitializeModbusMaster(SerialPort serialPort)
|
|
|
|
|
{
|
|
|
|
|
ModbusSerialMaster master = ModbusSerialMaster.CreateRtu(serialPort);
|
|
|
|
|
ConfigureModbusSettings(master); // Configure Modbus settings
|
|
|
|
|
return master; // Return the Modbus master
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void ConfigureModbusSettings(ModbusSerialMaster master)
|
|
|
|
|
{
|
|
|
|
|
WriteLine("Configuring Modbus settings...");
|
|
|
|
|
|
|
|
|
|
// Set sensor type and configuration
|
|
|
|
|
master.WriteSingleRegister(SlaveID, ModbusRegisters.AnalogInput1Sensor, 1);
|
|
|
|
|
master.WriteSingleRegister(SlaveID, ModbusRegisters.AnalogInput1SensorType, 11);
|
|
|
|
|
master.WriteSingleRegister(SlaveID, ModbusRegisters.AnalogInput1Decimal, 1);
|
|
|
|
|
|
|
|
|
|
// Set limits and modes for the Modbus device
|
|
|
|
|
SetSetPointLimits(master);
|
|
|
|
|
SetOutputFunction(master);
|
|
|
|
|
SetAnalogOutput(master);
|
|
|
|
|
SetTemperatureScale(master);
|
|
|
|
|
SetPowerFailureResponse(master);
|
|
|
|
|
SetOutputCycleTime(master);
|
|
|
|
|
SetCurrentDateTime(master);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void SetSetPointLimits(ModbusSerialMaster master)
|
|
|
|
|
{
|
|
|
|
|
ushort[] lowLimitRegisters = master.ReadInputRegisters(SlaveID, ModbusRegisters.AnalogInput1SetPointLowLimit, 1);
|
|
|
|
|
WriteLine("Setpoint low limit is {0}", lowLimitRegisters[0]);
|
|
|
|
|
|
|
|
|
|
ushort[] highLimitRegisters = master.ReadInputRegisters(SlaveID, ModbusRegisters.AnalogInput1SetPointHighLimit, 1);
|
|
|
|
|
WriteLine("Setpoint high limit is {0}", highLimitRegisters[0]);
|
|
|
|
|
|
|
|
|
|
master.WriteSingleRegister(SlaveID, ModbusRegisters.ProportionalBand, 5);
|
|
|
|
|
master.WriteSingleRegister(SlaveID, ModbusRegisters.SetPoint1, 1000);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void SetOutputFunction(ModbusSerialMaster master)
|
|
|
|
|
{
|
|
|
|
|
master.WriteSingleRegister(SlaveID, ModbusRegisters.Output1AFunction, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void SetAnalogOutput(ModbusSerialMaster master)
|
|
|
|
|
{
|
|
|
|
|
master.WriteSingleRegister(SlaveID, ModbusRegisters.AnalogOutput1AType, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void SetTemperatureScale(ModbusSerialMaster master)
|
|
|
|
|
{
|
|
|
|
|
master.WriteSingleRegister(SlaveID, ModbusRegisters.AnalogInputUnits, 0);
|
|
|
|
|
master.WriteSingleRegister(SlaveID, ModbusRegisters.TempScaleDisplay, 1);
|
|
|
|
|
master.WriteSingleRegister(SlaveID, ModbusRegisters.TempScale, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void SetPowerFailureResponse(ModbusSerialMaster master)
|
|
|
|
|
{
|
|
|
|
|
master.WriteSingleRegister(SlaveID, ModbusRegisters.PowerOutAction, 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void SetOutputCycleTime(ModbusSerialMaster master)
|
|
|
|
|
{
|
|
|
|
|
master.WriteSingleRegister(SlaveID, ModbusRegisters.Output1ACycleTimeType, 0);
|
|
|
|
|
|
|
|
|
|
ushort[] cycleTimeRegisters = master.ReadInputRegisters(SlaveID, ModbusRegisters.Output1ACycleTime, 1);
|
|
|
|
|
WriteLine("Output cycle time is {0}", cycleTimeRegisters[0]); // Display current cycle time
|
|
|
|
|
|
|
|
|
|
master.WriteSingleRegister(SlaveID, ModbusRegisters.Output1ACycleTime, 500); // Set new cycle time
|
|
|
|
|
|
|
|
|
|
cycleTimeRegisters = master.ReadInputRegisters(SlaveID, ModbusRegisters.Output1ACycleTime, 1);
|
|
|
|
|
WriteLine("Output cycle time is now {0}", cycleTimeRegisters[0]); // Confirm new cycle time
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void SetCurrentDateTime(ModbusSerialMaster master)
|
|
|
|
|
{
|
|
|
|
|
DateTime currentDateTime = DateTime.Now;
|
|
|
|
|
|
|
|
|
|
master.WriteSingleRegister(SlaveID, ModbusRegisters.CurrentDay, (ushort)currentDateTime.Day);
|
|
|
|
|
master.WriteSingleRegister(SlaveID, ModbusRegisters.CurrentMonth, (ushort)currentDateTime.Month);
|
|
|
|
|
master.WriteSingleRegister(SlaveID, ModbusRegisters.CurrentYear, (ushort)currentDateTime.Year);
|
|
|
|
|
master.WriteSingleRegister(SlaveID, ModbusRegisters.CurrentHour, (ushort)currentDateTime.Hour);
|
|
|
|
|
master.WriteSingleRegister(SlaveID, ModbusRegisters.CurrentMinute, (ushort)currentDateTime.Minute);
|
|
|
|
|
master.WriteSingleRegister(SlaveID, ModbusRegisters.CurrentSecond, (ushort)currentDateTime.Second);
|
|
|
|
|
|
|
|
|
|
WriteLine("Set F4 clock to {0} {1}", currentDateTime.ToLongTimeString(), currentDateTime.ToLongDateString()); // Display confirmation
|
2025-06-29 18:55:22 -04:00
|
|
|
|
}
|
2025-06-21 20:05:15 -04:00
|
|
|
|
}
|