locked
Serial Communication problem RRS feed

  • Question

  • Hello Guys!

    I am trying to create a connection between Microcontroller and PC. My controller sending data continuously and I try to display

     received data on the richTextbox by using DataReceived Event on my SerialPort.

    The problem is as follows:

    My controler sends this string: "Hello World!" with interval of 500ms.

    Data displayed on the richTextbox is "lo World" or this "llo World" or "ello World". Every time I receive the da

    data I lose part of it. Why?

    Here is my code:

    namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
            string ReceivedData;
            public Form1()
            {
                InitializeComponent();
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
                if (!serialPort1.IsOpen)
                {
                    serialPort1.Open();
                    label1.Text = "Serial port is open!";
                }
            }
    
            private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
            {
                ReceivedData = serialPort1.ReadExisting();
                this.Invoke(new EventHandler(DisplayText));
            }
            private void DisplayText(object o, EventArgs e)
            {
                richTextBox1.Text = ReceivedData;
            }
        }
    }
    

    • Moved by Mike Feng Monday, February 11, 2013 10:11 AM
    Sunday, February 10, 2013 5:13 PM

Answers

  • OK but then I lose part of received data. I don,t get the whole string. 

    You need to follow the protocol used by the MCU.

    When the DataReceived event is raised, it only means that some data has arrived at the input buffer.  It does not mean that an entire message has been received.  In fact, there is no way for the SerialPort to know what constitutes a message.  So you must take the data that is available then the event occurs and save it in your own buffer.  You continue to add data from the DataReceived event handler to the buffer until your entire message is received.  But it is up to you to analyze the contents of your buffer to determine when the message is finished.

    For example, if the MCU always sends "Hello World<Cr>" then you would look for the <Cr> character in the received data.  If it is found, any data before the <Cr> would be added to the existing buffer and then you would process the buffer, empty it, and add any remaining data after the <Cr> to the buffer as the beginning of a new message.

    So you have to know something about the format in which the MCU sends data so that you can determine how to analyze the received data and turn it into meaningful messages.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    • Proposed as answer by Carsten Kanstrup Tuesday, February 12, 2013 7:48 AM
    • Marked as answer by Mike Feng Saturday, February 23, 2013 11:00 AM
    Monday, February 11, 2013 5:54 PM

All replies

  • The problem may be due to a race condition.

    The serialport1_DataReceived event handler is fired by the serial port on a separate thread, so it can potentially fire twice very quickly, and every time it writes to the variable ReceivedData without perfrming any locking. DisplayText will run in the UI thread, so it is not synchronous with the call to this.Invoke that you are doing in DataReceived. Therefore, it may read incomplete, corrupted or overwritten data from ReceivedData.

    Sunday, February 10, 2013 5:51 PM
  • Thank you for reply!

    As you can see i am a beginner in C# programming and I don't get how to fix my code :(

    So what is the solution, How can I receive the all data without losing piece of it.

    Some example code would be very useful!

    Excuse my bad English!

    • Edited by rikotech Sunday, February 10, 2013 6:39 PM
    Sunday, February 10, 2013 6:32 PM
  • Try this modification:

    private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
    {
        string s = serialPort1.ReadExisting();
        this.Invoke(new Action<string>(DisplayText), s);
    }
    
    private void DisplayText(string s)
    {
        richTextBox1.AppendText(s);
    }
    

    Sunday, February 10, 2013 6:46 PM
  • I modified my code accordingly you suggestions, but an error has occurred.

    namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
            
            public Form1()
            {
                InitializeComponent();
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
                if (!serialPort1.IsOpen)
                {
                    serialPort1.Open();
                    label1.Text = "Serial port is open!";
                }
            }
    
            private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
            {
                string s = serialPort1.ReadExisting();
                this.Invoke(new Action<string>(DisplayText), s); //An error occur on this line
            }
            private void DisplayText(object o, EventArgs e)
            {
                richTextBox1.AppendText(s);
            }
        }
    }
    
    The error was: Error 1 No overload for 'DisplayText' matches delegate 'System.Action<string>'

    Sunday, February 10, 2013 7:09 PM
  • Change the arguments of DisplayText as shown before:

    private void DisplayText(string s)
    {
        richTextBox1.AppendText(s);
    }

    Sunday, February 10, 2013 7:20 PM
  • Thanks for reply!

    Ok I have something now but not what I exactly want. 

    Now I have multiple numbers stacked one after another like this

    But I want to see every time i get data only one updated number.The last number I get from SerialPort1. Remember only one number, not appended.

    I hope you understand me :)!

    Thank you again!


    • Edited by rikotech Sunday, February 10, 2013 7:57 PM
    Sunday, February 10, 2013 7:54 PM
  •  If you do not want to append text, then instead of ‘richTextBox1.AppendText(s)’ use ‘richTextBox1.Text = s’. You will see the last value that is returned by ReadExisting().

    Sunday, February 10, 2013 8:15 PM
  • OK but then I lose part of received data. I don,t get the whole string. 
    Sunday, February 10, 2013 8:18 PM
  • You have to decide how to join and interpret the information that is split by ReadExisting. To receive strings, consider ReadLine. (See the Documentation for details). There are other Read functions as well.


    • Edited by Viorel_MVP Sunday, February 10, 2013 8:24 PM
    Sunday, February 10, 2013 8:23 PM
  • When I use the other functions like readline() i don't get anything. In fact I don't know how to utilize those functions: readline() readByte() ext.
    Monday, February 11, 2013 5:42 PM
  • OK but then I lose part of received data. I don,t get the whole string. 

    You need to follow the protocol used by the MCU.

    When the DataReceived event is raised, it only means that some data has arrived at the input buffer.  It does not mean that an entire message has been received.  In fact, there is no way for the SerialPort to know what constitutes a message.  So you must take the data that is available then the event occurs and save it in your own buffer.  You continue to add data from the DataReceived event handler to the buffer until your entire message is received.  But it is up to you to analyze the contents of your buffer to determine when the message is finished.

    For example, if the MCU always sends "Hello World<Cr>" then you would look for the <Cr> character in the received data.  If it is found, any data before the <Cr> would be added to the existing buffer and then you would process the buffer, empty it, and add any remaining data after the <Cr> to the buffer as the beginning of a new message.

    So you have to know something about the format in which the MCU sends data so that you can determine how to analyze the received data and turn it into meaningful messages.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    • Proposed as answer by Carsten Kanstrup Tuesday, February 12, 2013 7:48 AM
    • Marked as answer by Mike Feng Saturday, February 23, 2013 11:00 AM
    Monday, February 11, 2013 5:54 PM
  • Nothing seems to be ODD in your approach, Check the Serial Port Setting like baud rate, parity, stop bits ,etc... correcting it will resolve ur prob

    It all Happenz Sendil

    Monday, February 11, 2013 6:24 PM
  • Thank you for reply!

    As I said I am a beginner in C# programming, so some hints like code example would be helpful!

    Monday, February 11, 2013 6:33 PM
  • Read Kimble has already given you the right hint.

    ReadExisting does not necessary return the full telegram. You need to collect the telegram yourself.

    Any communication must have a protocol, which makes it possible to separate the various telegrams - even in case of an error.

    If you use ASCII, you can just call ReadLine, which implements such a simple protocol as it returns when the NewLine character (default LF) is received.

    If you use binary data, there are more ways:

    This best way is to use Break, but unfortunately Microsoft is so "clever" as to take 11 bits from the UART including the break flag, then they use the flags to fire events, but after that they throws them away before the result is stored in a 16-bit stream, which could easily have contained the flags. The result is that this valuable information is lost and cannot be regained. The only way is to write your own driver or use for example an Exar USB-serial converter, which can return two bytes for every byte received (data and status).

    If you don't have a special UART or want to write drivers, you can for example take any value and define this as a synchronization value. Whenever this value occur in the telegram, you then insert a copy - except in the synchronization position. On the receiver side, the extra bytes must be removed. If there is no extra byte to remove, you have found the synchronization position.


    Everything should be made as simple as possible, but not simpler. Any fool can write code that a computer can understand. Good programmers write code that humans understand.



    Tuesday, February 12, 2013 8:06 AM