MSVS C#SerialPort接收数据丢失

时间:2016-02-25 19:34:49

标签: c# visual-studio bluetooth serial-port

我正在尝试使用C#在MSVS上创建一个串行通信工具。它与Photon MCU和蓝牙加密狗通信。

当按下“开始”按钮时,UI向Photon发送“1”,它首先发送当前时间戳并从函数发生器开始流数据。当按下“停止”按钮时,它首先发送10“2”(由于光子端的定时器问题),当光子接收时,它停止发送函数发生器的数据。然后它会休眠一秒并发送一个“3”,它会发送另一个当前时间戳。然后UI丢弃InBuffer中的数据并停止读取数据。

foreach($_POST['day'] as $key => $day) { $objects[] = (object)array('day' => $day, 'start' => $_POST['start'][$key], 'end' => $_POST['end'][$key]); } 与开始按钮相关联,connectBT与停止按钮相关联。

这是我现在的代码:

disconnectBT

我遇到了一个问题,当我按下“停止”按钮时,从蓝牙发送的最后一块数据丢失了。我没有收到按下停止按钮时我应该收到的最后一个时间戳。根据我们的数学计算,我们应该每秒接收500点(500Hz),但我只收到大约100点。

我的理论是UI正在以较慢(或延迟)的速率接收数据,并且SerialPort serial = new SerialPort(); string recieved_data; int startBuffer = 0; private void connectBT(object sender, RoutedEventArgs e) { startBuffer++; // keep track of BT open counter if (serial.IsOpen) Debug.WriteLine("BT Open"); // first time BT is open and BT is not open if (!serial.IsOpen) { if (startBuffer == 1) { // COM port properties serial.PortName = "COM7"; serial.BaudRate = 38400; serial.Handshake = Handshake.None; serial.Parity = Parity.None; serial.DataBits = 8; serial.StopBits = StopBits.One; serial.ReadTimeout = 200; serial.WriteTimeout = 50; serial.Open(); } startButton.Content = "Recording"; Send_Data("1"); // tell Photon to start sending data serial.DiscardInBuffer(); // discard whatever is in inbuffer serial.DataReceived += new SerialDataReceivedEventHandler(Recieve); // start receiving data } // after BT has been opened and start button has been pressed again else if (serial.IsOpen && startBuffer > 1) { startButton.Content = "Recording"; Send_Data("1"); serial.DiscardInBuffer(); serial.DataReceived += new SerialDataReceivedEventHandler(Recieve); } } // stop button is pressed private void disconnectBT(object sender, RoutedEventArgs e) { // send "2" ten times to tell photon to stop transmitting function generator data int i = 0; while (i < 10) { Send_Data("2"); Thread.Sleep(1); i++; } Thread.Sleep(1000); Send_Data("3"); // send a 3 to tell photon to send the last time stamp Thread.Sleep(1000); serial.DiscardInBuffer(); // discard in buffer serial.DataReceived -= Recieve; // stop receiving data //serial.Close(); // close BT startButton.Content = "Start"; } private void Recieve(object sender, SerialDataReceivedEventArgs e) { recieved_data = serial.ReadLine(); Debug.WriteLine(recieved_data); } 甚至在数据可以打印到Debug输出之前丢弃接收的数据。我知道由于与数据包相关的计数器值,我收到的第一个和最后一个之间的所有数据都在那里。基本上如果我收到1~500个数据点,我只收到1~100个数据点。我也尝试使用白蚁,发送1,2和3作为UI应该是,我得到所有数据,因为我需要它们。我没有故意关闭BT。

如何防止此数据丢失?我的代码中我做错了什么,我不应该做或正在做正确的蓝牙协议?这是我第一次写蓝牙代码,所以我对它很不熟悉。

2 个答案:

答案 0 :(得分:0)

不确定这是否是您问题的原因,但您的接收有一个很大的陷阱。

每个Receive事件只读取一行,并且在一个事件上可以有多行读取,然后在最后累积和丢弃它们。

ReadLine意味着以同步方式使用,就像流读取一行,然后处理它然后编写,而不是与DataReceived事件一起使用。

您有两种选择:使用serial.ReadLine()连续循环读取新线程(它将阻塞直到新行可用)或更好的方法,读取每个Receive事件的串行缓冲区。

要做到这一点,你可以这样做:

    List<byte> tmpBuffer = new List<byte>();
    static byte newLineB = Encoding.ASCII.GetBytes("\n")[0];

    void Receive(object sender, SerialDataReceivedEventArgs e)
    {

        lock (tmpBuffer)
        {
            while (serial.BytesToRead > 0)
            {
                byte[] segment = new byte[serial.BytesToRead];
                serial.Read(segment, 0, segment.Length);
                tmpBuffer.AddRange(segment);
                ProcessBuffer();

            }

        }

    }

    private void ProcessBuffer()
    {
        int index = 0;

        while ((index = tmpBuffer.IndexOf(newLineB)) > -1)
        {
            string line = Encoding.ASCII.GetString(tmpBuffer.Take(index + 1).ToArray());

            //Do whatever you need to do with the line data
            Debug.WriteLine(line);

            tmpBuffer.RemoveRange(0, index + 1);
        }
    }

如您所见,接收到的数据存储在用作缓冲区的时间列表中(是的,数组并使用缓冲区函数会更快,但对于小型消息,为简单起见,列表对于大多数情况来说已经足够了) ,然后将接收的数据添加到缓冲区,当没有剩余字节时,处理列表以搜索字符串行。

还要注意读取是循环的,我运行的情况是在执行函数时没有收到数据并且没有触发接收事件,所以最好是创建一个循环来读取还是数据。

答案 1 :(得分:0)

谢谢大家的回复,他们都帮我解决了我的问题,但最终解决了什么问题,延误了发送&#34; 3&#34;并丢弃我的inBuffer并关闭接收连接。

async Task DelayBT()
{
    await Task.Delay(100);
}

Thread.Sleep()因为其性质禁用线程中的所有操作(我仍然需要)而无法工作,所以这种方法就像魅力一样。我刚刚拨打await DelayBT,我需要延迟。

希望这可以帮助任何人遇到与我相同的问题。