Armoric的笔记 https://passport2.21ic.com/?357347 [收藏] [复制] [RSS] 160M虚拟示波器+10M任意信号发生器=EZDSO2041 正在热卖中。  提供完整的DLL动态库,方便在VB,VC,MATLAB,LABVIEW环境中进行二次开发。  一个电话,小莫为你真诚服务。15921793503  http://www.dzmi.com

日志

在C#中使用SerialPort类实现串口通信 遇到多线程问题

已有 16044 次阅读2010-1-17 12:23 |个人分类:单片机|系统分类:单片机

在C#中使用SerialPort类实现串口通信。

2009年11月01日 星期日 10:03






在.NET work 2.0中提供了SerialPort类,该类主要实现串口数据通信等。本文章将本人在学习过程中从网络上搜集到的相关信息写出来供大家参考。


下面主要介绍该类的主要属性(表1)和方法(表.2)。


如果需要了解更多的信息请登录http://msdn.microsoft.com/zh-cn/library/system.io.ports.serialport(VS.80).aspx查看。


相关文章


《使用System.IO.Ports读取COM口数据》


http://www.devasp.net/net/articles/display/727.html


使用SerialPort类的方法:


方法一:


首先要添加


using System.IO;
using System.IO.Ports;


1...在类的内部定义SerialPort com;


2...打开串口


            com = new SerialPort();
            com.BaudRate = 115200;
            com.PortName = "COM1";
            com.DataBits = 8;
            com.Open();//打开串口


3...发送数据


            Byte[] TxData ={1,2,3,4,5,6,7,8 };
            com.Write(TxData, 0, 8);


4...接收数据


     4.1使用事件接收


     this.com.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(this.OnDataReceived);


private void OnDataReceived(object sender, SerialDataReceivedEventArgs e)


    4.2使用线程接收


     接收数据启动一个线程,使其接收。


在类的内部定义


        Thread _readThread;
        bool _keepReading;


打开串口后启动线程


            _keepReading = true;
            _readThread = new Thread(ReadPort);
            _readThread.Start();


线程函数


view plaincopy to clipboardprint?
private void ReadPort()  
{  
    while (_keepReading)  
    {  
        if (com.IsOpen)  
        {  
            byte[] readBuffer = new byte[com.ReadBufferSize + 1];  
            try
            {  
                // If there are bytes available on the serial port,  
                // Read returns up to "count" bytes, but will not block (wait)  
                // for the remaining bytes. If there are no bytes available  
                // on the serial port, Read will block until at least one byte  
                // is available on the port, up until the ReadTimeout milliseconds  
                // have elapsed, at which time a TimeoutException will be thrown.  
                int count = com.Read(readBuffer, 0, com.ReadBufferSize);  
                String SerialIn = System.Text.Encoding.ASCII.GetString(readBuffer, 0, count);  
                if (count != 0)  
                    //byteToHexStr(readBuffer);  
                    Thread(byteToHexStr(readBuffer,count));  
            }  
            catch (TimeoutException) { }  
        }  
        else
        {  
            TimeSpan waitTime = new TimeSpan(0, 0, 0, 0, 50);  
            Thread.Sleep(waitTime);  
        }  
    }  
}
        private void ReadPort()
        {
            while (_keepReading)
            {
                if (com.IsOpen)
                {
                    byte[] readBuffer = new byte[com.ReadBufferSize + 1];
                    try
                    {
                        // If there are bytes available on the serial port,
                        // Read returns up to "count" bytes, but will not block (wait)
                        // for the remaining bytes. If there are no bytes available
                        // on the serial port, Read will block until at least one byte
                        // is available on the port, up until the ReadTimeout milliseconds
                        // have elapsed, at which time a TimeoutException will be thrown.
                        int count = com.Read(readBuffer, 0, com.ReadBufferSize);
                        String SerialIn = System.Text.Encoding.ASCII.GetString(readBuffer, 0, count);
                        if (count != 0)
                            //byteToHexStr(readBuffer);
                            Thread(byteToHexStr(readBuffer,count));
                    }
                    catch (TimeoutException) { }
                }
                else
                {
                    TimeSpan waitTime = new TimeSpan(0, 0, 0, 0, 50);
                    Thread.Sleep(waitTime);
                }
            }
        }


方法二:使用C#自带的SerialPor控件。


1...在“工具箱”的“组件”中选择SerialPor控件添加。


2...设置串口并打开


serialPort1.PortName = "COM1";


serialPort1.BaudRate = 9600;


serialPort1.Open();


3...写入数据可以使用Write或者下面的函数


serialPort1.WriteLine(str);


4...添加数据接收的事件


private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)


使用中的一些常见问题


C#中SerialPort类中DataReceived事件GUI实时处理方法(来自wanglei_wan@yahoo.com.cn 的看法)
MSDN:从 SerialPort 对象接收数据时,将在辅助线程上引发 DataReceived 事件。由于此事件在辅助线程而非主线程上引发,因此尝试修改主线程中的一些元素(如 UI 元素)时会引发线程异常。如果有必要修改主 Form 或 Control 中的元素,必须使用 Invoke 回发更改请求,这将在正确的线程上执行.进而要想将辅助线程中所读到的数据显示到主线程的Form控件上时,只有通过Invoke方法来实现
下面是代码实例:
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
   int SDateTemp = this.serialPort1.ReadByte();
   //读取串口中一个字节的数据
   this.tB_ReceiveDate.Invoke(  
//在拥有此控件的基础窗口句柄的线程上执行委托Invoke(Delegate)
//即在textBox_ReceiveDate控件的父窗口form中执行委托.
new MethodInvoker(           
/*表示一个委托,该委托可执行托管代码中声明为 void 且不接受任何参数的任何方法。 在对控件的 Invoke 方法进行调用时或需要一个简单委托又不想自己定义时可以使用该委托。*/
delegate{                
    /*匿名方法,C#2.0的新功能,这是一种允许程序员将一段完整代码区块当成参数传递的程序代码编写技术,通过此种方法可 以直接使用委托来设计事件响应程序以下就是你要在主线程上实现的功能但是有一点要注意,这里不适宜处理过多的方法,因为C#消息机制是消息流水线响应机制,如果这里在主线程上处理语句的时间过长会导致主UI线程阻塞,停止响应或响应不顺畅,这时你的主form界面会延迟或卡死      */                  
this.tB_ReceiveDate.AppendText(SDateTemp.ToString());//输出到主窗口文本控件
this.tB_ReceiveDate.Text += " ";}
    )
    );
}


如何知道当前电脑有哪个串口


在窗体上添加一个comboBox控件。


然后使用comboBox1.Items.AddRange(System.IO.Ports.SerialPort.GetPortNames()); 或者


string[] portList = System.IO.Ports.SerialPort.GetPortNames();
            for (int i = 0; i < portList.Length; ++i)
            {
                string name = portList;
                comboBox1.Items.Add(name);
            }


具体请参考http://msdn.microsoft.com/zh-tw/library/system.io.ports.serialport.getportnames.aspx


路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)