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(" 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; } } }