从串口解析/格式化数据 - C# [英] Parsing/formatting data from serial port - C#

查看:27
本文介绍了从串口解析/格式化数据 - C#的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我开发了一个监听串口的小程序.我的程序正在接收数据.问题是,它没有以所需的格式(一个字符串)显示它.我的程序接收的数据有两个字符串,例如:

I've developed a small program that listens to a serial port. My program is receiving data. The problem is, its not displaying it in the desired format (one string). The data my program is receiving comes in two strings, for example:

ID:34242 State:NY

邮编:12345 StreetType:Ave

Zip:12345 StreetType:Ave

它按块显示,并且一些数据被传递到下一行:

Its being displayed by chunks and some of the data is passed on to next lines as such:

 ID:34242
State:N
Y Zip:12
345 Street
Type:Ave

我已经使用 SerialDataReceive 事件处理程序来接收我的数据,它看起来像这样:

I have used the SerialDataReceive Event Handler to receive my data and it looks like this:

 private static void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {

        SerialPort spL = (SerialPort) sender;
        int bufSize = 20;
        Byte[] dataBuffer = new Byte[bufSize];
        Console.WriteLine("Data Received at"+DateTime.Now);
        Console.WriteLine(spL.Read(dataBuffer, 0, bufSize));
        string s = System.Text.ASCIIEncoding.ASCII.GetString(dataBuffer);
        Console.WriteLine(s);



    }

如您所见,我将字节检索到缓冲区中,创建一个字节数组来保存数据并使用 ASCII 编码将字节转换为字符串.我尝试使用 ReadLine() 但我的数据没有通过该函数显示.有谁知道将数据解析和格式化为一个字符串的任何其他方法?

As you can see, I retrieve the bytes into the buffer, create a byte array to hold the data and use ASCII encoding to translate the bytes into a string. I tried using ReadLine() but my data doesn't event get displayed with that function. Does anyone know of any other way to parse and format the data into one string?

推荐答案

问题是,正如您可能已经猜到的,一旦通过串行端口接收到数据,就会引发事件 DataReceived.那里可能没有完整的记录;SerialPort 对象不知道您认为哪些数据足够"重要或可行.

The problem is, as you may have guessed, that the event DataReceived is raised as soon as data has been received over the serial port. There may not be a complete record there; the SerialPort object has no clue what you consider to be "enough" data to be significant, or workable.

通常的解决方案是维护另一个接收数据的缓冲区",其中包含您认为不完整的任何数据.当数据通过端口进入并且您的事件触发时,它应该首先获取缓冲区中的内容并将其附加到您已经收到的内容中.然后,您应该从这个数据缓冲区的开头开始检查接收到的数据,寻找对您有意义的数据原子块"的已知模式;例如,假设您收到的第一件事是 "ID: 12".您将其放入缓冲区,然后扫描缓冲区以查找由正则表达式 "ID: d*?" 定义的模式.因为缓冲区中不存在尾随空格,所以您的模式无法找到任何有意义的东西,因此您现在知道您没有收到完整的消息.

The usual solution is to maintain another "buffer" of received data, containing any data you have recognized as incomplete. When data comes in over the port and your event fires, it should first take what's in the buffer and append it to what you have already received. Then, you should start at the beginning of this data buffer and inspect the received data, looking for known patterns of atomic "chunks" of data that have meaning to you; for instance, say the first thing you receive is "ID: 12". You take this, put it in the buffer, then scan the buffer looking for a pattern defined by a regex "ID: d*? ". Because the trailing space is not present in your buffer, your pattern fails to find anything of meaning, and so you now know you haven't received a full message.

然后,在下一次引发 DataReceived 事件时,将 "453 Sta" 拉出串行缓冲区.您将它附加到您已有的内容并获得 "ID:12453 Sta",当您应用正则表达式时,您将获得匹配ID:12345".您将其传递给进一步处理的方法(可能显示到控制台),并从缓冲区的前面删除相同的字符串,留下Sta".再次扫描你没有发现任何其他感兴趣的东西,所以你留下你所拥有的,循环重复 aws 数据继续进来.显然,你将测试更多的模式,而不仅仅是 ID 模式;您可以搜索您希望收到的整个字符串",例如 "ID: d*?State: w{2} ".您甚至可以将数据保留在缓冲区中,直到您有两个字符串作为记录: "ID:d*? State:w{2} Zip:d{5} StreetType:w*? ".

Then, on the next raising of the DataReceived event, you pull "453 Sta" out of the serial buffer. You append it to what you already have and get "ID:12453 Sta", and when you apply the regex, you get the match "ID: 12345 ". You pass this into a method for further processing (display to the console, maybe), and remove the same string from the front of the buffer, leaving "Sta". Scanning again you don't find anything else of interest, so you leave what you have, and the cycle repeats aws data continues to come in. Obviously, you'll be testing more patterns than just the ID pattern; you may search for an entire "string" you expect to receive, such as "ID: d*? State: w{2} ". You may even keep the data in your buffer until you have both strings for a record: "ID:d*? State:w{2} Zip:d{5} StreetType:w*? ".

无论哪种方式,您都需要确定接收到的数据是可靠的固定长度"(意味着特定类型的每个字符串始终具有相同数量的字节或字符),还是可靠的定界"(意味着会有一些字符或字符组合总是分隔数据的重要元素).如果这些都不适用,则可能很难将数据解析为单字段块.

Either way, you will need to identify whether the data being received is either reliably "fixed-length" (meaning each string of a particular type will always have the same number of bytes or characters), or reliably "delimited" (meaning there will be some character or character combination that always separates significant elements of data). If neither of these apply, it may be very difficult to parse the data into single-field chunks.

这是一个基于您已有的示例:

Here's a sample based on what you have already:

private static StringBuilder receiveBuffer = new StringBuilder();

private static void Port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{

    SerialPort spL = (SerialPort) sender;
    int bufSize = 20;
    Byte[] dataBuffer = new Byte[bufSize];
    Console.WriteLine("Data Received at"+DateTime.Now);
    Console.WriteLine(spL.Read(dataBuffer, 0, bufSize));
    string s = System.Text.ASCIIEncoding.ASCII.GetString(dataBuffer);
    //here's the difference; append what you have to the buffer, then check it front-to-back
    //for known patterns indicating fields
    receiveBuffer.Append(s);

    var regex = new Regex(@"(ID:d*? State:w{2} Zip:d{5} StreetType:w*? )");
    Match match;
    do{
       match = regex.Match(receiveBuffer.ToString());
       if(match.Success)
       {
          //"Process" the significant chunk of data
          Console.WriteLine(match.Captures[0].Value);
          //remove what we've processed from the StringBuilder.
          receiveBuffer.Remove(match.Captures[0].Index, match.Captures[0].Length);
       }
    } while (match.Success);
}

这篇关于从串口解析/格式化数据 - C#的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆