在c#中使用线程读取COM端口

时间:2011-12-20 03:17:33

标签: c# multithreading serial-port

我想要一些关于线程的建议,因为我是新手。我已经阅读了几篇关于在线线程的文章。

我正在阅读com端口数据。我想使用线程,以便它每5秒读取一次数据并更新列表框中的数据。目前,正在读取所有数据。 我不确定从哪里开始。

我应该从哪里开始我的线程代码?我正在使用Windows Form,c#VS2008。

这是我从com端口读取数据的代码:

    void datareceived(object sender, SerialDataReceivedEventArgs e)
    {            
        myDelegate d = new myDelegate(update);
        listBox1.Invoke(d, new object[] { });

    }


    public void update()
    {           

        while (serialPortN.BytesToRead > 0)
            bBuffer.Add((byte)serialPortN.ReadByte());
        ProcessBuffer(bBuffer);

    }

    private void ProcessBuffer(List<byte> bBuffer)
    {            

        int numberOfBytesToRead = 125;

        if (bBuffer.Count >= numberOfBytesToRead)
        {            


                listBox1.Items.Add("SP: " + (bBuffer[43].ToString()) + "  " + " HR: " + (bBuffer[103].ToString()));


            // Remove the bytes read from the list
            bBuffer.RemoveRange(0, numberOfBytesToRead);

        }

    }        

全部谢谢!

1 个答案:

答案 0 :(得分:2)

为什么不使用计时器?将它放入适当的表单的InitializeComponent方法

using System.Timers;

private void InitializeComponent()
{
    this.components = new System.ComponentModel.Container();
    this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
    this.Text = "Form1";

    Timer timer = new Timer();

    timer.Interval = 5000;
    timer.Elapsed += new ElapsedEventHandler(TimerElapsed);

    //timer.Enabled = true; // you may need this, but probably not if you are calling the start method.
    timer.Start();
}

void TimerElapsed(object sender, ElapsedEventArgs e)
{
    // put your code here to read the COM port
}

此代码的唯一其他问题是您将获得异常跨线程操作无效。

你必须像这样修改你的代码,

private void ProcessBuffer(List<byte> bBuffer)
{
    int numberOfBytesToRead = 125;

    if (bBuffer.Count >= numberOfBytesToRead)
    {
        this.Invoke(new Action(() =>
        {
            listBox1.Items.Add("SP: " + (bBuffer[43].ToString()) + "  " + " HR: " + (bBuffer[103].ToString()));
        });

        // Remove the bytes read from the list
        bBuffer.RemoveRange(0, numberOfBytesToRead);
    }
}

原因是ProcessBuffer方法将在后台线程上运行。后台线程无法访问UI线程上的UI组件。因此,您必须调用this.Invoke,它将对UI线程上的列表框运行该更新。

如果您想了解有关Invoke方法的更多信息,请查看此处

http://msdn.microsoft.com/en-us/library/zyzhdc6b.aspx

更新:

所以在TimerElapsed方法中你需要调用你的代码,但我不清楚它应该调用哪部分代码?什么是'datareceived'方法,在您的代码段中没有任何调用它。

所以我猜它会是这个,

void TimerElapsed(object sender, ElapsedEventArgs e)
{
    Update();
}

public void Update()
{
    while (serialPortN.BytesToRead > 0)
        buffer.Add((byte)serialPortN.ReadByte());
    ProcessBuffer(buffer);
}

调用ProcessBuffer方法没有意义,因为缓冲区来自何处?

如果我不在正确的轨道上,可能会扩展您的代码示例,我很乐意提供更多帮助。

请注意我对你的代码做了一些样式更改(随意接受或保留它们),C#中的方法应该以大写字母开头,而调用变量bBuffer在C#中不是标准的。另一点如果该方法仅在类中调用,则应将其设为私有。