Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/visual-studio/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MSVS C#串行端口接收到的数据丢失_C#_Visual Studio_Bluetooth_Serial Port - Fatal编程技术网

MSVS C#串行端口接收到的数据丢失

MSVS C#串行端口接收到的数据丢失,c#,visual-studio,bluetooth,serial-port,C#,Visual Studio,Bluetooth,Serial Port,我正在尝试使用C#在MSV上创建一个串行通信工具。它与光子MCU和蓝牙加密狗通信 当按下“开始”按钮时,UI向光子发送“1”,它首先发送当前时间戳,并从函数生成器开始流式传输数据。当按下“停止”按钮时,它首先发送10“2”s(由于光子端的计时器问题),当光子接收时,它停止发送函数生成器的数据。然后它休眠一秒钟并发送一个“3”,它发送另一个当前时间戳。然后UI丢弃InBuffer中的数据并停止读取数据 connectBT与启动按钮相连,disconnectBT与停止按钮相连 这是我现在拥有的代码:

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

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

connectBT
与启动按钮相连,
disconnectBT
与停止按钮相连

这是我现在拥有的代码:

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);

}
SerialPort serial=new SerialPort();
接收数据的字符串;
int startBuffer=0;
私有void connectBT(对象发送方,路由目标)
{
startBuffer++;//跟踪BT打开计数器
if(serial.IsOpen)Debug.WriteLine(“BT打开”);
//第一次英国电信开放和英国电信未开放
如果(!serial.IsOpen)
{
如果(开始缓冲==1)
{
//COM端口属性
serial.PortName=“COM7”;
串行波特率=38400;
串行.握手=握手.无;
串行。奇偶校验=奇偶校验。无;
serial.DataBits=8;
serial.StopBits=StopBits.One;
serial.ReadTimeout=200;
serial.WriteTimeout=50;
serial.Open();
}
startButton.Content=“录制”;
Send_Data(“1”);//告诉光子开始发送数据
serial.DiscardInBuffer();//丢弃inbuffer中的任何内容
serial.DataReceived+=新的SerialDataReceivedEventHandler(receive);//开始接收数据
}
//在BT被打开并再次按下启动按钮后
否则如果(serial.IsOpen&&startBuffer>1)
{
startButton.Content=“录制”;
发送_数据(“1”);
serial.DiscardInBuffer();
serial.DataReceived+=新的SerialDataReceivedEventHandler(receive);
}
}
//按下停止按钮
专用void disconnectBT(对象发送器,RoutedEventArgs e)
{
//发送“2”十次,通知光子停止传输函数生成器数据
int i=0;
而(i<10)
{
发送_数据(“2”);
睡眠(1);
i++;
}
睡眠(1000);
Send_Data(“3”);//发送一个3,告诉光子发送最后一个时间戳
睡眠(1000);
serial.DiscardInBuffer();//在缓冲区中丢弃
serial.DataReceived-=receive;//停止接收数据
//serial.Close();//关闭BT
startButton.Content=“开始”;
}
私有void receive(对象发送方,SerialDataReceivedEventArgs e)
{
接收的_数据=serial.ReadLine();
Debug.WriteLine(接收的_数据);
}
我遇到了一个问题,当我按下“停止”按钮时,从蓝牙发送的最后一块数据丢失了。当按下停止按钮时,我从未收到我应该收到的最后一个时间戳。根据我们的数学,我们应该每秒收到500点(500Hz),但我只收到大约100点

我的理论是,UI以较慢(或延迟)的速率接收数据,并且在数据可以打印到调试输出之前,
serial.DiscardInBuffer
丢弃接收到的数据。我知道,由于与数据包相关联的计数器值,我收到的第一个和最后一个数据包之间的所有数据都在那里。基本上,如果我接收1~500个数据点,我只接收1~100个。我也试过用termite发送1、2和3作为UI应该是的,我得到了我需要的所有数据。我不是故意关闭BT的


我可以做些什么来防止数据丢失?对于正确的蓝牙协议,我在代码中做了哪些不应该做或应该做的错误?这是我第一次编写蓝牙代码,所以我对它相当不熟悉。

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

每个接收事件只读取一行,并且在一个事件上可以有多行要读取,然后它们将被累积并最终丢弃

ReadLine旨在以一种同步方式使用,就像一个流,在其中读取一行,处理它,然后写入,而不是与DataReceived事件一起使用

您有两个选项:使用serial.ReadLine()在连续循环读取中旋转新线程(它将阻塞,直到新行可用),或者更好的方法是在每个接收事件上读取串行缓冲区

要这样做,您可以这样做:

    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);
        }
    }
List tmpBuffer=newlist();
静态字节newLineB=Encoding.ASCII.GetBytes(“\n”)[0];
无效接收(对象发送方,SerialDataReceivedEventArgs e)
{
锁(tmpBuffer)
{
而(serial.BytesToRead>0)
{
byte[]段=新字节[serial.BytesToRead];
串行读取(段,0,段.长度);
tmpBuffer.AddRange(段);
ProcessBuffer();
}
}
}
私有void ProcessBuffer()
{
int指数=0;
而((index=tmpBuffer.IndexOf(newLineB))>-1)
{
string line=Encoding.ASCII.GetString(tmpBuffer.Take(index+1.ToArray());
//对行数据执行任何需要执行的操作
Debug.WriteLine(行);
tmpBuffer.removange(0,索引+1);
}
}
如您所见,接收到的数据存储在用作缓冲区的临时列表中(是的,数组和使用缓冲区函数会更快,但对于小消息和简单起见,列表对于大多数情况来说就足够了),然后将接收到的数据添加到缓冲区中,当
async Task DelayBT()
{
    await Task.Delay(100);
}