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 internal class Program { // Modbus Register Addresses for various parameters private static class ModbusRegisters { 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 } // Configuration for Modbus Slave ID private const byte SlaveID = 1; private static void Main(string[] args) { try { using SerialPort serialPort = InitializeSerialPort(); using ModbusSerialMaster master = InitializeModbusMaster(serialPort); MonitorProcessValues(master); } catch (Exception ex) { WriteLine($"Initialization error: {ex.Message}"); } } private static void MonitorProcessValues(ModbusSerialMaster master) { while (true) { if (KeyAvailable && ReadKey(true).Key == ConsoleKey.Escape) { WriteLine(" pressed. Exiting..."); break; } try { 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 } } } 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 { 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 } }