串口数据的读取与显示

串口数据的读取与显示

 

假设有一个一边,不断的通过端口发送数据,每八位算作一组,其中有一位的ASCII码对应字符为“=”,现在要将它显示到TextBox控件上

现在面临两个问题,如何读取串口数据,如何将串口数据显示在TextBox上。

为了能够简要的说明问题,这里并没有对接收的数据做特殊处理而只是直接显示在TextBox控件上。

 

1.串口数据的读取

读取串口数据是通过串口控件进行的,在工具箱中选择SerialPort,将它拖放到窗口控件上就可以了,此时,在串口下端,会显示串口控件的实例名称,本例为serialPort1:

SerialPort控件2

 

有了SerialPort控件实例之后,要对它的一些属性进行设置,但是设置之前首先判断端口是否打开,如果打开,则先关闭端口,然后才能进行设置,设置完毕后再打开端口。这个过程中用到了SerialPort的下面两个方法:

  • Open       打开一个新的串行端口连接。
  • Close       关闭端口连接,将 IsOpen 属性设置为 false,并释放内部 Stream 对象。

其中有几个比较重要的属性:

  • PortName  获取或设置通信端口,包括但不限于所有可用的 COM 端口。
  • BaudRate  获取或设置串行波特率。
  • IsOpen      获取一个值,该值指示 SerialPort 对象的打开或关闭状态。
  • ReceivedBytesThreshold  获取或设置 DataReceived 事件发生前内部输入缓冲区中的字节数。

对应程序如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
if (serialPort1.IsOpen)
{
    serialPort1.Close();
}
//设置波特率为1200
serialPort1.BaudRate = 1200;
//设置端口号,这里使用COM1端口
  serialPort1.PortName = "COM1";
//设置 DataReceived 事件发生前内部输入缓冲区中的字节数为8
serialPort1.ReceivedBytesThreshold = 8;
 
//textChanged += new UpdateTextEventHandler(ChangeText);
 
try
{
    serialPort1.Open();
}
catch (System.Exception ex)
{
    MessageBox.Show("未能打开端口,请检查是否已经连接串口.\n" + ex.Message);
}

现在已经对SerialPort控件做了一些设置,设置完毕之后,这时如果端口有数据发来,那么就会触发DataRecieved事件,通过监听这个事件,就可以对发送过来的数据进行接收。双击属性页的DataRecieved即可,如图:

SerialPort控件3事件这样就会自动添加DataRecieved事件处理函数:

1
2
3
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{           
}

在事件处理函数中,调用SerialPort的Read方法读取数据,Read方法如下:

名称 说明
SerialPort.Read (Byte[], Int32, Int32) 从 SerialPort 输入缓冲区读取一些字节并将那些字节写入字节数组中指定的偏移量处。
SerialPort.Read (Char[], Int32, Int32) 从 SerialPort 输入缓冲区读取一些字节并将那些字节写入到字节数组中指定的偏移量处。
 

本程序中我们声明了一个Byte数组receivedData用来接收串口发送来的数据。要把Byte[]转化成String可以使用Encoding.ASCII.GetString()方法,它返回String。然后再清空SerialPort控件的Buffer,以便接收后面发来的数据.

1
2
3
serialPort1.Read(receivedData, 0, 8);
string text = Encoding.ASCII.GetString(receivedData);
serialPort1.DiscardInBuffer();

然后再用这个返回的String设置TextBox的Text属性,但是不能直接在DataRecieved事件处理函数中设置,因为DataRecieved事件处理函数发生在另一个线程中。这就带来了第二个问题,如何将数据显示在TextBox上。

 

2.将串口数据的显示在TextBox上

上面我们已经得到了串口读取的数据text,也知道不能直接将它在DataRecieved事件处理方法中设置给TextBox,为了能够将它传递给TextBox,我们需要使用窗口类的Invoke方法

通过调用委托(Delegate),并且将参数以数组的形式(Object[])传递给委托,就能使用委托里面的方法。

这里使用了委托的概念,本文不对此做深入介绍,简单来说就是声明一个委托,再用委托声明事件,最后将事件处理方法添加给事件即可,但是要注意,添加的事件处理方法的参数列表必须与委托的参数列表相同:

1
2
3
4
5
6
7
8
9
//定义委托
    private delegate void UpdateTextEventHandler(string text);
    //定义事件
    private event UpdateTextEventHandler textChanged;
    //事件处理方法
    private void ChangeText(string text)
    {
        textBox1.Text = text;//设置textBox1的Text
    }
1
<font face="微软雅黑">在构造方法中,将事件处理方法添加到事件上:</font>
1
2
//将事件处理方法添加到事件中去
textChanged += new UpdateTextEventHandler(ChangeText);

最后,在DataRecieved事件中通过Invoke调用事件:

1
this.Invoke(textChanged, new string[] { text });

这样就串口发送的数据就能显示在TextBox控件上了.

SerialPort运行结果 

1
//Form1.cs源码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
namespace SerialPortTest
{
    public partial class Form1 : Form
    {
        private byte[] receivedData = new byte[8];
        //定义委托
        private delegate void UpdateTextEventHandler(string text);
        //定义事件
        private event UpdateTextEventHandler textChanged;
        //事件处理方法
        private void ChangeText(string text)
        {
            textBox1.Text = text;
        }
        public Form1()
        {
            InitializeComponent();
            if (serialPort1.IsOpen)
            {
                serialPort1.Close();
            }
            //设置波特率为1200
            serialPort1.BaudRate = 1200;
            //设置端口号,这里使用COM1端口
            serialPort1.PortName = "COM1";
            //设置 DataReceived 事件发生前内部输入缓冲区中的字节数为8
            serialPort1.ReceivedBytesThreshold = 8;
 
            //将事件处理方法添加到事件中去
            textChanged += new UpdateTextEventHandler(ChangeText);
 
            try
            {
                serialPort1.Open();
            }
            catch (System.Exception ex)
            {
                MessageBox.Show("未能打开端口,请检查是否已经连接串口.\n" + ex.Message);
            }
 
        }
 
        private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {           
                serialPort1.Read(receivedData, 0, 8);
                string text = Encoding.ASCII.GetString(receivedData);
                serialPort1.DiscardInBuffer();
                this.Invoke(textChanged, new string[] { text });
        }
         
    }
}
 
 
分类: C#
 
绿色通道: 好文要顶 关注我 收藏该文与我联系 
1
0
 
(请您对文章做出评价)
 
« 博主上一篇:Python学习笔记——String、Sequences
» 博主下一篇:How to Write an ActiveX Control
posted @ 2011-03-08 11:05 在路上的理想 阅读(3392) 评论(4编辑 收藏
 

 
#1楼 2012-04-24 16:16 一坨黄色  
我用了你的例子在电脑上试了一下,为什么textbox什么都不显示呢?
#2楼[楼主2012-06-27 08:29 liulixiang  
@一坨黄色
你没有连接串口,可以从网上下载一个虚拟串口,然后用串口助手与你的程序进行通信即可
#3楼 2012-07-07 12:36 posaty  
楼主的代码都可以理解。但有一个问题一直不解:我们用网上下载的串口助手每次都可以接受8个字节以上的数据,但无论是Read(char[],0,n)还是ReadExisting()都一次最多只能读取8字节,而超过8字节就会再次触发DataReceived事件。虽然ReadLine()可以对字节数没有限制,但必须要用换行符做结束标志。所以想和楼主交流下:如何一次最多读取8字节以上的数据?
#4楼[楼主2012-07-09 12:30 liulixiang  
@posaty
设置ReceivedBytesThreshold属性,这个属性定义了当缓冲区接收的数据多大时进行触发DataReceived事件,比如你把它设置为16,那你每次ReadExisting()至少是16个字

posted on 2013-04-29 22:44  song2013  阅读(11735)  评论(2编辑  收藏  举报

导航