从C#中的串口读取

时间:2009-03-13 23:19:23

标签: c# compact-framework serial-port

我已经尝试过使用Readline()并且数据被删除,我尝试使用Read()但是我不知道如何使用它的错误验证方法,因为我可能会一个接一个地获得几个数据包而我没有知道将有另一个数据包进入的方式。在数据包BytesToRead之间是0,所以我不能使用它。当读取数据到缓冲区时你有一个定时器或者让线程进入休眠状态以允许所有数据包到达?

我迷路了。不知道下一步该尝试什么。

我应该提一下,我不能保证从串口流出的字符串将以\ n或\ r或\ r \ n结束。当用户按下PRINT时,我只需要一种简单的方法来读取将来自秤的所有数据包。

有人在这里回答了我喜欢的想法 - 等待所有数据包的一定时间,但他们删除了他们的答案。你有可能重新发布它吗?

3 个答案:

答案 0 :(得分:22)

您是否尝试过收听DataRecieved课程的SerialPort事件?

public class MySerialReader : IDisposable
{
    private SerialPort serialPort;
    private Queue<byte> recievedData = new Queue<byte>();

    public MySerialReader()
    {
        serialPort = new SerialPort();
        serialPort.Open();

        serialPort.DataReceived += serialPort_DataReceived;
    }

    void serialPort_DataReceived(object s, SerialDataReceivedEventArgs e)
    {
        byte[] data = new byte[serialPort.BytesToRead];
        serialPort.Read(data, 0, data.Length);

        data.ToList().ForEach(b => recievedData.Enqueue(b));

        processData();
    }

    void processData()
    {
        // Determine if we have a "packet" in the queue
        if (recievedData.Count > 50)
        {
            var packet = Enumerable.Range(0, 50).Select(i => recievedData.Dequeue());
        }
    }

    public void Dispose()
    {
        if (serialPort != null)
            serialPort.Dispose();
    }

答案 1 :(得分:10)

我们不久前经历了同样的过程。

读取“数据包”的唯一方法是有一些关于它们的开始和结束位于流中的概念。

来自msdn

  

因为SerialPort类缓冲数据,并且BaseStream属性中包含的流没有,所以两者可能会争用可读取的字节数。 BytesToRead属性可以指示有要读取的字节,但BaseStream属性中包含的流可能无法访问这些字节,因为它们已缓冲到SerialPort类。

我们使用了一个背景线程(你可以使用BackgroundWorker)将数据读入缓冲区。 如果你不能使用SerialPort.Newline属性可靠地设置终止字符(因为它会变化!)那么你将需要实现自己的数据包检测系统,因为你无法使用阻塞的SerialPort.Readline()方法

您可以使用SerialPort.Read()(或使用SerialPort.ReadExisting()方法的字符串)读入字节缓冲区,并在检测到数据中的有效数据包时生成事件。请注意,Read()(我假设ReadExisting())清空了SerialPort的缓冲区,因此您需要将数据保存在其他位置。

如果设置了SerialPort.ReadTimeout,则可以处理TimeoutException,并可以轻松处理设备未传输的情况。如果您使用固定数量的字节或其他一些非终止方案,这是重置数据包检测的好方法。 (如果不需要部分数据包,请在超时时使用SerialPort.DiscardInBuffer())。

祝你好运

答案 2 :(得分:3)

由于字节可能随时进入,因此缓冲传入数据至关重要。所以你应该

  1. 缓冲传入的数据
  2. 扫描缓冲区以查找完整数据
  3. 从缓冲区中删除已使用的数据
  4. 我只是想知道你是否仍然遇到串口问题。如果是这样,我在C#中开发了一个串口编程语言,我相信它几乎可以解决每个人遇到的所有问题。

    请你试试看吧?例如;您可以缓冲来自串口的传入数据,如下所示,并轻松执行字符串操作。

    state Init
      // define a global variable
      our $BUFFER = "";
      jump(Receive);
    end state
    
    state Receive
      recv();
      $len = length($DATA_PACKET);
      if("$len > 0") {
        $BUFFER += $DATA_PACKET;
        call(Parser);
      }
    end state
    
    state Parser
      // check if buffer matchs regular expression pattern
      if(match($BUFFER, "(?<WILLDELETE>.*?<STX>(?<DATA>.*?)<ETX>(?<CHECKSUM>[0-9A-F]{2}))")) {
        // Received complete data
        $lenData = length($WILLDELETE);
        $BUFFER = remove($BUFFER, 0, $lenData);
    
        // Do operations with the other parsed fields. $DATA and $CHECKSUM in this example.
      }
    end state
    

    项目可以在sourceforge上免费获得,如果您有任何疑问,请随时提出。

    Project Homepage

    Download Link