Share Serial Port Devices Over Ethernet with Eltima Serial to Ethernet Connector
Figure 1: Sharing Serial Port Devices over Network
Serial to Ethernet Connector allows sharing of numerous RS232/RS422/RS485 serial interface devices over network, be it Ethernet LAN or Internet. You can turn your PC into a server with multiple clients which can be locally or at remote location, they can all access a device connected to the server PC’s COM Port as if they were connected directly. This COM Port can either be a physical or a virtual COM Port.
You can also connect two applications installed in different PCs via LAN or Internet, or work with serial port devices on a virtual machine in case the software that suppose to control the serial device does not support the operating system of the server PC.
What’s so amazing about this software, you can generate as many virtual COM ports as you need, there is no limit on the number and connections that you can create and these virtual COM ports behave exactly like physical COM ports.
Serial communication is the oldest and still popular communication protocol, many devices especially industrial devices still support this type of protocol. It’s cheaper and easy to work with, you can develop a software to communicate with a serial device quicker compared to other communication protocols like Ethernet for example.
With this in mind, the possibilities are limitless there are many Serial to Ethernet Connector usage scenarios, you can learn more from Eltima website:
In this review, we are going to consider one scenario to monitor your serial COM Port device remotely over TCP/IP Network. This project is based on our previous project, Ethernet UDP-Based Control and Monitoring with PIC Microcontroller. In this project we learned how to control and monitor devices connected to a PIC microcontroller from a remote PC.
In this project, our device does not have an Ethernet controller like many other devices, only the simple COM Port which will be connected to a PC server where we’re gonna install the Serial to Ethernet Connector software to share our COM Port over TCP/IP Network.
Figure 2: Project Circuit Diagram
A temperature sensor is connected to the PIC analog channel 0, will read the ambient temperature every 2 seconds and send the temperature value to the server PC. we’re gonna develop a custom TCP client software that will be installed in a remote client PC to display the temperature read from the server graphically and plot a live chart of the temperature variations continuously.
Below is the microcontroller code using mikroC compiler.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | /********************************************************************* Project Name: Serial to Ethernet Connector:TCP Server Connection Author: Bitahwa Bindu (c) www.studentcompanion.co.za , February 2019 Test configuration: MCU: PIC18F45K22 Oscillator: 8MHz Compiler: mikroC Pro for PIC v7.1.0 **********************************************************************/ bit flag; //Declare local Flag variable //Timer0 //Prescaler 1:64; TMR0 Preload = 3036; Actual Interrupt Time : 2 s //Place/Copy this part in declaration section void InitTimer0(){ T0CON = 0x85; TMR0H = 0x0B; TMR0L = 0xDC; GIE_bit = 1; TMR0IE_bit = 1; } void Interrupt(){ if (TMR0IF_bit){ TMR0IF_bit = 0; TMR0H = 0x0B; TMR0L = 0xDC; flag = 1; } } // // Start of MAIN program // void main() { unsigned int temperature; float mV; unsigned char txt[4]; flag = 0; InitTimer0(); //// Initialize Timer0 ANSELA = 1; // Configure PORTA as Analog ANSELC = 0; // Configure PORTC pins as digital TRISA.RA0 = 1; //Configure RA0 as input UART1_Init(9600); // Initialize UART module at 19200 bps Delay_ms(100); // Wait for UART module to stabilize ADC_Init(); // Initialize ADC while(1) // Loop forever { //Get temperature value and send it to remote PC every 2 seconds if (flag) //Check if there is an Interrupt call { temperature = ADC_Read(0); //Get 10-bit results of AD Conversion mV= temperature * 5000.0/1023.0; // Convert to mV mV = mV/10.0; //Convert mV to temperature in Celcius FloatToStr( mV,txt); //Convert Temperature to string // send Temperature to remote PC using Serial to ethernent connector UART1_Write_Text(txt); flag=0; } } } |
TCP Server Connection
What I have admired about this Serial to Ethernet Connector software is its simplicity, to create a new Server connection is very simple, only very simple steps and you are good to go:
- Select New connection → Server connection on the toolbar
- Specify the connection name.
- Choose the local COM port to be used in the connection.
- Check Create as virtual port if you want a virtual COM port to be created for this connection.Virtual ports work exactly like real ones and fully emulate their settings. Their main advantage is speed and also the fact that you can create any number of virtual ports you want and with arbitrary names.
- In the TCP port field set the port on which you want the server to listen for client connections.
Note: The TCP port you select should be allowed by your firewall and should not be already in use by another application. - Configure the advanced settings, if needed.
- Press Create connection
And that’s all, you can also configure the advanced settings if needed depending on your unique requirements. Figure 3 below shows our Serial to Ethernet Connector server settings.
Figure 3: Eltima Serial Ethernet Connection
We used a Virtual COM1, the server is listening on port 10002. Below is the settings:
For more information to learn how to configure the TCP Server connection, please read the online user guide:
Client Graphical User Interface (GUI) Software
Figure 6 below shows the Client GUI software.
Figure 6: Client Graphical User Interface (GUI) Software
A temperature gauge displays the temperature from the server graphically and plot a live chart of the temperature variations continuously. The software is developed with Microsoft C#.
A TCP-Client socket connection is created to connect to the server IP address and port number. In serverThread(), we read the temperature data from the server continuously.
For more information and to download a trial copy of the Serial to Ethernet Connector, please visit Eltima Software website:
Below is the complete code of the application. You can also download the full Visual studio project at the end of this article.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 | using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using DevExpress.XtraEditors; using System.Net.Sockets; using System.Net; using DevExpress.XtraGauges.Win.Gauges.Circular; using DevExpress.XtraGauges.Core.Model; using System.Threading; using DevExpress.XtraCharts; namespace UDP_Control_Monitoring { public partial class Form1 : DevExpress.XtraBars.Ribbon.RibbonForm { //Load IP Address and Port number public string ServerIPAddress = Properties.Settings.Default.IPaddress.ToString(); public int PortNumber =Convert.ToInt16( Properties.Settings.Default.PortNumber); //Clock ArcScaleComponent scaleMinutes, scaleSeconds; int lockTimerCounter = 0; public Form1() { InitializeComponent(); //clock scaleMinutes = Clock.AddScale(); scaleSeconds = Clock.AddScale(); scaleMinutes.Assign(scaleHours); scaleSeconds.Assign(scaleHours); arcScaleNeedleComponent2.ArcScale = scaleMinutes; arcScaleNeedleComponent3.ArcScale = scaleSeconds; timer1.Start(); timer1_Tick(null, null); linearScaleComponent1.Value = 0; //initialize scale to 0 //chart timer2.Interval = interval; } void UpdateClock(DateTime dt, IArcScale h, IArcScale m, IArcScale s) { int hour = dt.Hour < 12 ? dt.Hour : dt.Hour - 12; int min = dt.Minute; int sec = dt.Second; h.Value = (float)hour + (float)(min) / 60.0f; m.Value = ((float)min + (float)(sec) / 60.0f) / 5f; s.Value = sec / 5.0f; } private void btnExit_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e) { Environment.Exit(Environment.ExitCode); } bool connected = false; private void btnConnect_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e) { try { btnDisconnect.Visibility = DevExpress.XtraBars.BarItemVisibility.Always; btnConnect.Visibility = DevExpress.XtraBars.BarItemVisibility.Never; barStaticConnect.Caption = "Connected!"; btnDisconnectImage.Visibility = DevExpress.XtraBars.BarItemVisibility.Always; btnConnectImage.Visibility = DevExpress.XtraBars.BarItemVisibility.Never; connected = true; } catch (Exception ex) { XtraMessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void btnDisconnect_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e) { try { btnDisconnect.Visibility = DevExpress.XtraBars.BarItemVisibility.Never; btnConnect.Visibility = DevExpress.XtraBars.BarItemVisibility.Always; barStaticConnect.Caption = "Disconnected!"; btnDisconnectImage.Visibility = DevExpress.XtraBars.BarItemVisibility.Never; btnConnectImage.Visibility = DevExpress.XtraBars.BarItemVisibility.Always; PauseResume(); } catch (Exception ex) { XtraMessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void timer1_Tick(object sender, EventArgs e) { if (lockTimerCounter == 0) { lockTimerCounter++; UpdateClock(DateTime.Now, scaleHours, scaleMinutes, scaleSeconds); lockTimerCounter--; } } private void btnSettings_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e) { frmSettings frm = new frmSettings(); frm.ShowDialog(); } private void Form1_Load(object sender, EventArgs e) { Thread thdTCPServer = new Thread(new ThreadStart(serverThread)); CheckForIllegalCrossThreadCalls = false; thdTCPServer.Start(); } float temp; public void serverThread() { TcpClient client = new TcpClient(ServerIPAddress, PortNumber); NetworkStream nwStream = client.GetStream(); while (true) { if (client.Available > 0) { //---read back the text--- byte[] bytesToRead = new byte[client.ReceiveBufferSize]; int bytesRead = nwStream.Read(bytesToRead, 0, 5); if (connected) { try { if (bytesRead > 0) { string returnData = Encoding.ASCII.GetString(bytesToRead, 0, bytesRead); // label1.Text = returnData; temp = float.Parse(returnData, System.Globalization.CultureInfo.InvariantCulture.NumberFormat); linearScaleComponent1.Value = temp; } } catch (Exception ex) { XtraMessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } } } } const int interval = 3; static RegressionLine GetRegressionLine(Series series) { if (series != null) { SwiftPlotSeriesView swiftPlotView = series.View as SwiftPlotSeriesView; if (swiftPlotView != null) foreach (Indicator indicator in swiftPlotView.Indicators) { RegressionLine regressionLine = indicator as RegressionLine; if (regressionLine != null) return regressionLine; } } return null; } int TimeInterval { get { return Convert.ToInt32(spnTimeInterval.EditValue); } } Series Series1 { get { return chart.Series.Count > 0 ? chart.Series[0] : null; } } RegressionLine Regression1 { get { return GetRegressionLine(Series1); } } void SetPauseResumeButtonText() { btnPauseResume.Text = timer2.Enabled ? "Pause" : "Resume"; } private void timer2_Tick(object sender, EventArgs e) { if (Series1 == null ) return; DateTime argument = DateTime.Now; SeriesPoint[] pointsToUpdate1 = new SeriesPoint[interval]; for (int i = 0; i < interval; i++) { pointsToUpdate1[i] = new SeriesPoint(argument, temp); argument = argument.AddMilliseconds(1); } DateTime minDate = argument.AddSeconds(-TimeInterval); int pointsToRemoveCount = 0; foreach (SeriesPoint point in Series1.Points) if (point.DateTimeArgument < minDate) pointsToRemoveCount++; if (pointsToRemoveCount < Series1.Points.Count) pointsToRemoveCount--; AddPoints(Series1, pointsToUpdate1); if (pointsToRemoveCount > 0) { Series1.Points.RemoveRange(0, pointsToRemoveCount); } SwiftPlotDiagram diagram = chart.Diagram as SwiftPlotDiagram; if (diagram != null && (diagram.AxisX.DateTimeScaleOptions.MeasureUnit == DateTimeMeasureUnit.Millisecond || diagram.AxisX.DateTimeScaleOptions.ScaleMode == ScaleMode.Continuous)) diagram.AxisX.WholeRange.SetMinMaxValues(minDate, argument); } void AddPoints(Series series, SeriesPoint[] pointsToUpdate) { if (series.View is SwiftPlotSeriesViewBase) series.Points.AddRange(pointsToUpdate); } private void PauseResume() { timer2.Enabled = !timer2.Enabled; SetPauseResumeButtonText(); } private void btnPauseResume_Click(object sender, EventArgs e) { PauseResume(); } private void chRegression_CheckedChanged_1(object sender, EventArgs e) { if (Regression1 != null) Regression1.Visible = chRegression.Checked; } } } |
You can download the full project files below. All the files are zipped, you will need to unzip them (Download a free version of the Winzip utility to unzip files).
Proteus Schematic Project: TCP_Ethernet_Proteus_Project
MikroC Source Code: USART_Monitoring_MikroC
PC GUI Software Project: TCP-Client_Monitoring_PC_Application