I have connected a sensor to serial port of PC and want to read incoming data from Serial port in C#.
Below is code snippet. I tried to iterate through all the ports and open each port to check if device is connected to any port so that i can read data from that port.
However, none of the port return any data. "sp_DataReceived" event never get fired.

//serial port def
        SerialPort sp;

        //delegate to write to textbox
        delegate void Write2UI(string text); 

        private void Form1_Load(object sender, EventArgs e)
        {
            try
            {
                string[] sps = SerialPort.GetPortNames();
                foreach (string pname in sps)
                {
                    sp = new SerialPort(pname);
                    sp.DtrEnable = true;
                    sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
                    sp.Open();
                    Thread.Sleep(3000);
                }
            }
            catch (Exception er)
            {
                MessageBox.Show(er.Message);
            }
        }

        void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            String test = sp.ReadExisting();
            this.BeginInvoke(new Write2UI(dataReceived), new object[] { test });
        }

        private void dataReceived(string text)
        {
            textBox1.Text = text.Trim();
        }

any help is appreciated.

I see a problem right away with garbage collection in your code.

Take this portion of your code:

SerialPort sp;
        private void Form1_Load(object sender, EventArgs e)
        {
                string[] sps = SerialPort.GetPortNames();
                foreach (string pname in sps)
                {
                    sp = new SerialPort(pname);
        }

Now lets expand it to something that is functionally identical, but more clearly shows the problem:

SerialPort sp;
        private void Form1_Load(object sender, EventArgs e)
        {
          sp = new SerialPort("COM1");
          sp = new SerialPort("COM2");
        }

When you assign sp = COM2 the reference for the serial port instance on COM1 is lost. Since you have nothing referencing the first SerialPort class you instantiated it is candidate for garbage collection. If it is garbage collected then no events are fired because it will close the connection and free the unmanaged resources.

The next problem is this:

this.BeginInvoke(new Write2UI(dataReceived), new object[] { test });

This code calls the dataReceived delegate on another thread (not your GUI thread). Inside of the code of dataReceived you're modifying a control. You cannot access controls from another thread, they need to be accessed on the thread that created the code (your GUI thread). Using asynchronous delegates will not throw an exception that you see in the debugger. If you look in the "output" window of the IDE you can see the exception but it won't cause the debugger to break.

You will want to do something like this:

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;
using System.IO.Ports;

namespace daniweb
{
  public partial class frmSerial5 : Form
  {
    private List<SerialPort> ports;

    public frmSerial5()
    {
      InitializeComponent();
    }

    private void frmSerial5_Load(object sender, EventArgs e)
    {
      ports = new List<SerialPort>();
      string[] portNames = SerialPort.GetPortNames();
      foreach (string s in portNames)
      {
        SerialPort sp = new SerialPort(s);
        sp.DtrEnable = true;
        sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
        sp.Open();
        ports.Add(sp); //Hang on to all the references of our serial port collection
      }
    }

    private void button1_Click(object sender, EventArgs e)
    {
      foreach (SerialPort sp in ports)
      {
        sp.Write("PING");
      }
    }

    void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
      //Gets the serial port firing the event
      SerialPort sp = (sender as SerialPort);
      string data = sp.ReadExisting();

      //Calls the delegate asynchronously on another thread
      new Action<string>(DataReceived).BeginInvoke( 
        data,
        null,
        null);
    }

    private void DataReceived(string s)
    {
      //Executes the code on your GUI thread
      this.textBox1.Invoke(new MethodInvoker( 
        delegate()
        {
          textBox1.Text += s + Environment.NewLine;
        }
      ));
    }
  }
}

Edited 7 Years Ago by sknake: n/a

This article has been dead for over six months. Start a new discussion instead.