如何从串口获得多行结果

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何从串口获得多行结果相关的知识,希望对你有一定的参考价值。

我正在使用winform项目并尝试将命令发送到串行端口并从中接收数据。我期待一个多行响应,但使用下面的代码我只得到响应的第一行。我不想使用ReadExisting

{
    SerialPort mySerialPort = new SerialPort("COM5");

    mySerialPort.BaudRate = 115200;
    mySerialPort.Parity = Parity.None;
    mySerialPort.StopBits = StopBits.One;
    mySerialPort.DataBits = 8;
    mySerialPort.Handshake = Handshake.None;
    mySerialPort.DtrEnable = true;
    mySerialPort.RtsEnable = true;

    mySerialPort.Open();

    var command = Command.Authentication.GetStringValue();
    mySerialPort.WriteLine(command);               

    mySerialPort.DataReceived += new SerialDataReceivedEventHandler(_serialPort_DataReceived);

    string _response = mySerialPort.ReadLine();

    mySerialPort.Close();
}       

void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    SerialPort sp = (SerialPort)sender;
    sp.ReadLine();
}

我的回答如下:

REQ: SUCCESS
REQ: MAC_ADDR:000D6F111C5DB14C
REQ: FWINFO: Build 01
REQ: HWINFO: Gen3 R0c

我试过了:

{
    _serialPort = new SerialPort(
        _currentSerialSettings.PortName = Home.PortName,
        _currentSerialSettings.BaudRate,
        _currentSerialSettings.Parity,
        _currentSerialSettings.DataBits,
        _currentSerialSettings.StopBits);

    _serialPort.Open();

    //send command
    _serialPort.WriteLine(Command.Get_Device_List.GetStringValue());

    Thread t = new Thread(ReadThread);            
    t.Start(_serialPort);
}

private void ReadThread(object context)
{
    SerialPort serialPort = context as SerialPort;

    while (serialPort.IsOpen)
    {
        string inData = serialPort.ReadLine();
        Debug.WriteLine(inData);                
    }
}

以下是两个问题:

  1. 我想在上层方法中获取数据,而不是在ReadThread中。
  2. 它没有给出最后的数据。

我错过了什么吗?

旁注:如果我多次使用mySerialPort.ReadLine();,那么我能够捕获整个响应,但响应可能因命令而异。目前,当数据不存在时,它会在ReadLine上崩溃

答案

我很少尝试

  1. 要使此异步,您希望使用DataReceived事件
  2. 您应该在发送命令之前监听DataReceived事件。
  3. DataReceived事件使用名为ReceivedBytesThreshold的属性。在我的示例代码中,我将其设置为1.这意味着如果串行缓冲区中有一个或多个字节,则会引发DataReceived事件。

您会注意到,在DataReceived事件中,您希望尽可能快地读取缓冲区中的每个数据字节。

class Program
{

    static void Main(string[] args)
    {
        var serial = Setup();

        // send your command from here
        //var command = Command.Authentication.GetStringValue();
        //serial.WriteLine(command);

        Console.ReadLine();
    }



    static SerialPort Setup()
    {
        SerialPort serialport = new SerialPort("COM5");

        serialport.BaudRate = 115200;
        serialport.Parity = Parity.None;
        serialport.StopBits = StopBits.One;
        serialport.DataBits = 8;
        serialport.Handshake = Handshake.None;
        serialport.DtrEnable = true;
        serialport.RtsEnable = true;
        serialport.ReceivedBytesThreshold = 1;


        serialport.DataReceived += serialPort_DataReceived;
        serialport.Open();
        return serialport;
    }

    private static void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        var s = (SerialPort) sender;
        int n;
        var data = new List<byte>();
        do
        {
            n = s.BytesToRead;
            var buffer = new byte[n];

            try
            {
                var size = s.Read(buffer, 0, buffer.Length);
                data.AddRange(buffer);

            }
            catch (Exception ex)
            {

            }

        } while (n > 0);


        // you should raise your own event passing your data to your ui to exit this method
        // for demo only
        var yourdata  = Encoding.ASCII.GetString(data.ToArray());
        Console.WriteLine(yourdata);

    }
}
另一答案

请尝试以下代码。使用异步读取并在处理命令之前等待行尾返回:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            SerialPort _serialPort = new SerialPort("COM5");

            _serialPort.BaudRate = 115200;
            _serialPort.Parity = Parity.None;
            _serialPort.StopBits = StopBits.One;
            _serialPort.DataBits = 8;
            _serialPort.Handshake = Handshake.None;
            _serialPort.DtrEnable = true;
            _serialPort.RtsEnable = true;

            _serialPort.DataReceived += (AsyncRead);
            _serialPort.Open();


        }
        string inputData = "";
        private void AsyncRead(object sender, SerialDataReceivedEventArgs e)
        {
            SerialPort serialPort = sender as SerialPort;
            string inData = serialPort.ReadExisting();
            inputData += inData;

            int returnIndex = inputData.IndexOf('
');
            if(returnIndex >= 0)
            {
                string command = inputData.Substring(0, returnIndex);
                //remove command from inputData
                inputData = inputData.Substring(returnIndex + 1);

                //test if command is just a return
                if (command.Length > 0)
                {
                    ProcessCommand(command);
                }
            }
        }
        private void ProcessCommand(string inputLine)
        {
        }

    }
}

带队列和计时器的代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;

namespace WindowsFormsApplication8
{
    public partial class Form1 : Form
    {
        static List<string> queue = new List<string>();
        public Form1()
        {
            InitializeComponent();
            Timer timer1 = new Timer();
            timer1.Tick += new EventHandler(timer1_Tick);
            timer1.Interval = 500;
            timer1.Start();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            SerialPort _serialPort = new SerialPort("COM5");

            _serialPort.BaudRate = 115200;
            _serialPort.Parity = Parity.None;
            _serialPort.StopBits = StopBits.One;
            _serialPort.DataBits = 8;
            _serialPort.Handshake = Handshake.None;
            _serialPort.DtrEnable = true;
            _serialPort.RtsEnable = true;

            _serialPort.DataReceived += (AsyncRead);
            _serialPort.Open();


        }
        string inputData = "";
        private void AsyncRead(object sender, SerialDataReceivedEventArgs e)
        {
            SerialPort serialPort = sender as SerialPort;
            string inData = serialPort.ReadExisting();
            inputData += inData;

            int returnIndex = inputData.IndexOf('
');
            if (returnIndex >= 0)
            {
                string command = inputData.Substring(0, returnIndex);
                //remove command from inputData
                inputData = inputData.Substring(returnIndex + 1);

                //test if command is just a return
                if (command.Length > 0)
                {
                    queue.Add(command);
                }
            }
        }
        private void timer1_Tick(object sender, EventArgs e)
        {

            if (queue.Count > 0)
            {
                string command = queue[0];
                queue.RemoveAt(0);
            }
        }

    }
}

以上是关于如何从串口获得多行结果的主要内容,如果未能解决你的问题,请参考以下文章

如何使用接口将活动回调返回到片段

scalajs-react:如何从状态对象的 Seq 中获得多行文本字段?

原子片段:原子编辑器中的多行片段

如何使用导航架构组件从片段中获取结果?

在 MySQL PHP 中从多行结果中分离行

如何使用mysql IN语句获取多行[关闭]