C# Problem with receiving all data using serial port

Karlsson 1 Reputation point
2022-09-18T11:57:07.68+00:00

I have a program in C# using windows forms to send data bytes using COM ports. First of all I decided to test the program on 1 computer, on two interconnected USB modules supporting serial communication, so that one transmits, the other receives and vice versa. I run the .exe file twice for this and just set one COM on one port, and the other on the other.
YRZei.png

Here is the first version of code - it allows to send hex numbers from 00 to FF.

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 System.IO.Ports;  
  
namespace USB_tester  
{  
 /// <summary>  
 /// Description of MainForm.  
 /// </summary>  
 public partial class USB_tester : Form  
 {  
  
        System.IO.Ports.SerialPort port;  
        delegate void Delegat1();  
        Delegat1 moj_del1;  
 public USB_tester()  
 {  
            InitializeComponent();  
  
            port = new SerialPort();  
  
            port.ReadTimeout = 500;  
            port.WriteTimeout = 500;  
  
            Settings.Enter += new EventHandler(Ustawienia_Enter);  
            port.DataReceived += new SerialDataReceivedEventHandler(DataRecievedHandler);  
            moj_del1 = new Delegat1(WpiszOdebrane);  
 }  
 private void DataRecievedHandler(object sender, SerialDataReceivedEventArgs e)  
        {  
            rtbTerminal.Invoke(moj_del1);  
        }  
  
        private void WpiszOdebrane()  
        {  
            ColoredTerminal(rtbTerminal, port.ReadByte().ToString("X") + " ", System.Drawing.Color.Blue);  
        }  
  
 private void ColoredTerminal(System.Windows.Forms.RichTextBox RichTextBox, string Text, System.Drawing.Color Color)  
        {  
            var StartIndex = RichTextBox.TextLength;  
            RichTextBox.AppendText(Text);  
            var EndIndex = RichTextBox.TextLength;  
            RichTextBox.Select(StartIndex, EndIndex - StartIndex);  
            RichTextBox.SelectionColor = Color;  
        }  
  
        void Ustawienia_Enter(object sender, EventArgs e)  
        {  
              
            this.cbName.Items.Clear();  
            this.cbParity.Items.Clear();  
            this.cbStop.Items.Clear();  
            foreach (String s in SerialPort.GetPortNames()) this.cbName.Items.Add(s);  
            foreach (String s in Enum.GetNames(typeof(Parity))) this.cbParity.Items.Add(s);  
            foreach (String s in Enum.GetNames(typeof(StopBits))) this.cbStop.Items.Add(s);  
  
  
            cbName.Text = port.PortName.ToString();  
            cbBaud.Text = port.BaudRate.ToString();  
            cbData.Text = port.DataBits.ToString();  
            cbParity.Text = port.Parity.ToString();  
            cbStop.Text = port.StopBits.ToString();  
        }  
        void ButSendClick(object sender, EventArgs e)   
        {   
            if (port.IsOpen)   
            {   
                ColoredTerminal(rtbTerminal, ((Int32)numericSend.Value).ToString("X") + " ", System.Drawing.Color.Black);   
                Byte[] tosend = { (Byte) numericSend.Value};   
                port.Write(tosend, 0, 1);   
            }   
            else System.Windows.Forms.MessageBox.Show("Make connection first");   
        }  
          
 void TabPage1Click(object sender, EventArgs e)  
 {  
  
 }  
 void Label1Click(object sender, EventArgs e)  
 {  
  
 }  
 void Label3Click(object sender, EventArgs e)  
 {  
  
 }  
 void Label4Click(object sender, EventArgs e)  
 {  
  
 }  
 void ButDefault(object sender, EventArgs e)  
 {  
  
 }  
 void CbNameSelectedIndexChanged(object sender, EventArgs e)  
 {  
  
 }  
 void CbBaudSelectedIndexChanged(object sender, EventArgs e)  
 {  
  
 }  
 void RtbTerminalTextChanged(object sender, EventArgs e)  
 {  
  
 }  
 void ButRefreshClick(object sender, EventArgs e)  
 {  
  
 }  
 void ButDefaultClick(object sender, EventArgs e)  
 {  
     this.cbName.Text = "COM3";  
            this.cbName.Text = "COM4";  
            this.cbBaud.Text = "9600";  
            this.cbData.Text = "8";  
            this.cbParity.Text = "None";  
            this.cbStop.Text = "One";  
 }  
 void ButCancelClick(object sender, EventArgs e)  
 {  
         cbName.Text = port.PortName.ToString();   
            cbBaud.Text = port.BaudRate.ToString();   
            cbData.Text = port.DataBits.ToString();   
            cbParity.Text = port.Parity.ToString();   
            cbStop.Text = port.StopBits.ToString();  
 }  
 void PbStatusClick(object sender, EventArgs e)  
 {  
  
            if (port.IsOpen)   
            {   
                pbStatus.BackColor = System.Drawing.Color.Red;   
                port.Close();   
                labStatus.Text = "No connection";   
                ColoredTerminal(rtbTerminal, "\nConnection end - " + port.PortName + "\n", System.Drawing.Color.Orange);   
            }   
  
            {   
                  
                try   
                {   
                    port.PortName = this.cbName.Text;   
                    port.BaudRate = Int32.Parse(this.cbBaud.Text);   
                    port.DataBits = Int32.Parse(this.cbData.Text);   
                    port.Parity = (Parity)Enum.Parse(typeof(Parity), this.cbParity.Text);   
                    port.StopBits = (StopBits)Enum.Parse(typeof(StopBits), this.cbStop.Text);   
  
                    port.Open();   
  
                    pbStatus.BackColor = System.Drawing.Color.Green;   
                    labStatus.Text = "Active connection (port:" + port.PortName.ToString() + ", speed: " + port.BaudRate.ToString() + ", data bits: " +   
                    port.DataBits.ToString() + "\n stop bits: " + port.StopBits.ToString() + ", parity: " + port.Parity.ToString() + ")";   
                    ColoredTerminal(rtbTerminal, "Connection started - " + port.PortName + "\n", System.Drawing.Color.Orange);   
                }   
  
                catch(Exception exc)   
                {   
                    MessageBox.Show("Connection error:\n" + exc.Message);   
                }   
            }   
 }  
 void LabStatusClick(object sender, EventArgs e)  
 {  
  
 }  
  
  
  
 }  
}  

...and it works quite ok - left terminal send hex number - and the right one can receive this.

0FqIK.png

So I decided to modify a code to be able to send random data in series, byte by byte. For example, I wanted to send 100 hex characters one by one - so I modified a code. I replaced:

void ButSendClick(object sender, EventArgs e)   
{   
    if (port.IsOpen)   
    {   
        ColoredTerminal(rtbTerminal, ((Int32)numericSend.Value).ToString("X") + " ", System.Drawing.Color.Black);   
        Byte[] tosend = { (Byte) numericSend.Value};   
        port.Write(tosend, 0, 1);   
    }   
    else System.Windows.Forms.MessageBox.Show("Make connection first");   
}  

with:

void ButSendClick(object sender, EventArgs e)  
 {  
             if (port.IsOpen)   
            {   
             Random rnd = new Random();  
             for (int i = 0; i <= 100; i++)  
             {  
  
             int num = rnd.Next(0,255);  
     string hexString = num.ToString("X2");  
                ColoredTerminal(rtbTerminal, hexString + " ", System.Drawing.Color.Black);   
                Byte[] tosend = BitConverter.GetBytes(num);   
                port.Write(tosend, 0, 1);   
             }  
            }   
            else System.Windows.Forms.MessageBox.Show("Make connection first");   
 }  

... and now something's wrong - only a few characters will be sent after pressing the Send button.

njcak.png

The next "part" of characters will be sent after pressing the Send button again, but the number of characters sent on the left grows much faster:

zxSIj.png

I would like the number of characters on the left after pressing the Send button once to be equal to the number of characters received. Meanwhile, these signs are suppressed somewhere (in a buffer?) along the way and they are sent only after the next button is pressed. What could this be the reason of? I will be grateful for every tip.

Windows Forms
Windows Forms
A set of .NET Framework managed libraries for developing graphical user interfaces.
1,827 questions
Windows
Windows
A family of Microsoft operating systems that run across personal computers, tablets, laptops, phones, internet of things devices, self-contained mixed reality headsets, large collaboration screens, and other devices.
4,741 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,235 questions
0 comments No comments
{count} votes

3 answers

Sort by: Most helpful
  1. Viorel 112.1K Reputation points
    2022-09-18T13:29:37.86+00:00

    Maybe inside the WpiszOdebrane you must use a loop, which checks the value of port.BytesToRead and reads all of available bytes.

    1 person found this answer helpful.

  2. abdul theep 0 Reputation points
    2023-04-05T15:51:22.8333333+00:00

    Try to call flush on the port after each write, maybe it is not sent.

    0 comments No comments

  3. Gustavo Doello 0 Reputation points
    2023-11-08T17:00:52.1066667+00:00

    I had the same problem but in Visual Basic, even it's another languaje, it's the same api, and is well documented that has theese problems. Basically the bug consists in that the DataRecived event is triggered, almost randomly, before the end line and CR chars are received (chr(10)+chr(13)), then a unique data string received could triggers the data received event many times, instead of just only one, as it should.

    I've solved in a simply way, i've declared a global variable for the (complete) string received, then in the procedure that handles the data received event, i've used an "if" that checks if the chr(10) is included in the recived string. If not (that means tha it's an incomplete substring), i simply add the received (sub)string to the global variable string (without processing it), when at end the chr(10) is included in the (sub)string received, i proceed to add it to the global string (the same as the other substrings received before), then proccess that global string as a unique data received string and finally blank it in order to start with the next data arrival.

    It means that, until the chr(10) is received i just ad the substrings to de global string , when the chr(10) arrives, i proceed to process the global string as a unique string received data.

    I hope that this solution works for you. Sorry for my limited english. good luck.

    0 comments No comments