C # Windows form - строка синтаксического анализа, полученная от последовательного порта - PullRequest
0 голосов
/ 30 декабря 2018

Я разрабатываю приложение Windows Form с использованием C #, в котором я получаю данные из последовательного порта, и на данный момент у меня есть следующий код (это просто соответствующий код для моей проблемы):

private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)     
{
      ReceivedData = serialPort1.ReadExisting();
      this.Invoke(new EventHandler(interp_string));       
}

private void interp_string(object sender, EventArgs e)      
{
      textReceive.Text += ReceivedData + "\n";
}

Но теперь мне нужно разобрать полученные данные в небольшую строку.Переменная ReceivedData представляет собой комбинацию нескольких строк в следующем формате: «значение времени \ n», где значение изменяется от 0 до 1024, а время указывается в секундах (и всегда увеличивается) и имеет 4 десятичных знака.Мне нужно разделить переменную ReceivedData на отдельные значения, и пришло время отобразить ее на графике.Принимая во внимание, что при использовании ReadExisting может случиться так, что одна строка будет прочитана только частично, а остальная будет прочитана только в следующий раз, когда сработает событие DataReceived, но я не против, если я потеряю одну точку данных,не имеет решающего значения.

Я уже пытался использовать ReadLine вместо ReadExisting, и мне удалось разделить каждую строку и отобразить данные, но, учитывая большой объем данных, которые получает приложение, одна строка в 1 мс,приложение не может идти в ногу, и хотя прошло 10 секунд, приложение все еще печатает данные со 2-й секунды, и я нажимаю кнопку, чтобы прекратить получать данные, приложение долго сохраняет значения печати, которые, как я предполагаю, являютсяте, которые хранятся в приемном буфере.А переход на ReadExisting был единственным методом, который я нашел для чтения и печати всего в реальном времени.

Ответы [ 2 ]

0 голосов
/ 01 января 2019

Событие DataReceived может возникать в середине строки, и вы, возможно, еще не получили сообщение целиком.Вам нужно будет знать, что вы ищете, как правило, перевод строки (LF) или возврат каретки (CR).Я использую StringBuilder для построения своих строк, ниже приведен пример, где LF означает, что я получил все сообщение.Я добавляю символы в свою строку, пока не узнаю, что у меня есть целое сообщение.Я быстро очищаю буфер, потому что ваша следующая строка может появиться во время оценки.В этом простом примере я просто вызываю функцию для оценки моей строки, но вы можете использовать делегата здесь.

StringBuilder sb = new StringBuilder();
char LF = (char)10;

private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
    string Data = serialPort1.ReadExisting();

    foreach (char c in Data)
    {
        if (c == LF)
        {
            sb.Append(c);

            CurrentLine = sb.ToString();
            sb.Clear();

            //do something with your response 'CurrentLine'
            Eval_String(CurrentLine);
        }
        else
        {
            sb.Append(c);
        }
    }
}

Как только вы получите сообщение целиком, вы сможете оценить его для того, что вам нужно.,Я не уверен, как выглядят ваши данные, но в моем примере мое сообщение возвращается через запятую, поэтому я могу разбить строку на массив строк, используя запятую в качестве разделителя, и получить каждое значение из сообщения.

public void Eval_String(string s)
{
    string[] eachParam;
    eachParam = s.Split(',');

    if (eachParam.Length == 5)
    {
        //do something
        Console.WriteLine(eachParam[2]);
    }
}

Редактировать: Вот пример того, как обновить ваш графический интерфейс с помощью очереди.

StringBuilder sb = new StringBuilder();
char LF = (char)10;
Queue<string> q = new Queue<string>();

private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
    string Data = serialPort1.ReadExisting();

    foreach (char c in Data)
    {
        if (c == LF)
        {
            sb.Append(c);

            CurrentLine = sb.ToString();
            sb.Clear();

            q.Enqueue(currentLine);
        }
        else
        {
            sb.Append(c);
        }
    }
}

private void backgroundWorkerQ_DoWork(object sender, DoWorkEventArgs e)
{
    while (true)
    {
        if (backgroundWorkerQ.CancellationPending)
            break;

        if (q.Count > 0)
        {
            richTextBoxTerminal.AppendText(q.Dequeue());
        }

        Thread.Sleep(10);
    }
}

Если вы никогда не работали с фоновым рабочим, вам просто нужно создать нового фонового рабочегообъект, установите supportsCancellation в true, затем добавьте событие для его DoWork.Затем, когда вы запускаете форму, вы можете сообщить ей .RunWorkerAsync().

if (!backgroundWorkerQ.IsBusy)
{
    backgroundWorkerQ.RunWorkerAsync();
}

См .: https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.backgroundworker?view=netframework-4.7.2 Также обратите внимание, что backgroundworker находится в своем собственном потоке, и вам, скорее всего, потребуется BeginInvokeэто обновить текстовое поле.

0 голосов
/ 31 декабря 2018

Вы всегда можете обратиться к регулярному выражению в типах String вместо того, чтобы разбивать каждую строку в одиночку. Regex .NET , Метод соответствий

Предположим, у вас есть эти перехваченные данные:

1250 154873210
1250 15487556574
1250 15487444
1250 154871111
1250 154875454524545444
1250 154873210
1250 15487556574
1250 15487444
1250 154871111
1250 154875454524545444
1250 154873210
1250 15487556574
1250 15487444
1250 154871111
1250 154875454524545444
1250 154873210
1250 15487556574
1250 15487444
1250 154871111
89877 154875454524545444
001 154873210
877 15487556574
15647 15487444
540 154871111
12 154875454524545444

с регулярным выражением было бы легко получить парные значение / время в результате (как упомянуто в ссылке выше).

Таким образом, ваш обычный будет:

(?'Value'\d+)\s*(?'Time'\d+\.\d+)

Демо

C # Пример:

        string ReceivedData = "1221 1111.1111\n1221 1111.1111";
        MatchCollection matches = Regex.Matches(ReceivedData, @"(?'Value'\d+)\s*(?'Time'\d+\.\d+)");
        Console.WriteLine("Matches found : "+matches.Count);
        foreach(Match Pairs in matches)
        {

            Console.WriteLine(String.Format("Match : Value -> {0} , Time -> {1}", Pairs.Groups["Value"], Pairs.Groups["Time"]));
        }
...