c# winform ,大片机接收缓存有限,串口向单片机发送大量数据时,只会执行前面的内容,后面的数据全部丢失

目前逻辑是,单片机执行完一行指令回返回一个ok。
上位机收到一个ok值则计数-1
上位机每发送一行数据都计数+1,发送前为判断计数是否超过某个值,超过则暂停发送,直到收到ok,计数满足要求。

请问代码哪里有问题。
补充:现在的问题好像跟跨线程有关,手动逐行发送计数都没问题。通过按钮事件循环发送,发送事件没结束前,接收数据事件没法执行。

      //点击发送按钮事件,逐行发送listBoxgcode中全部内容
      private void simpleButton12_Click(object sender, EventArgs e)
       {
           send_rows = 0;//已发送行数
            for (int i = 0; i < listBoxgcode.Items.Count; i++)
            {
    serialPort1.Write(listBoxgcode.Items[i].ToString() + "\r");//回车符为单片机识别的结束位,需加上
    send_rows += 1;//每发送一行,计数+1

                while (send_rows > 30)//发送行数大于30行则停留在此循环
                 {
                    System.Threading.Thread.Sleep(100);//延时0.1s
                  }
             }
        }




    /// 串口接收数据事件,收到一个ok,则send_rows-1
    private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
    string mystring = serialPort1.ReadExisting();
    if (mystring.Contains("ok"))
        send_rows -= 1;

    getmystring = new getstring(DoUpdate_tbRecieve);    //调用tbrecieve委托事件
    Invoke(getmystring, mystring);
}
catch (Exception EX)
{
    MessageBox.Show(EX.Message, "出错", MessageBoxButtons.OK, MessageBoxIcon.Error);
    return;
}

}

首先确认两个函数是否在同一个线程执行,可以打印线程的id查看,如果是在同一个线程执行的那不用想,肯定是得全部发送完才能接收。再说说下来的问题:
1.假如是同一个线程执行的,那你的发送次数如果超过30不用想程序就像傻了一样在while里死循环,而且界面处于“未响应”的假死状态
2.假如是不同线程执行的,那么最起码你应该给计数的变量加上锁,保证原子操作

从逻辑上看,你这个程序就是发送不能超过30条,而接收端接收到后会给程序发信号,表示总数减一;
从你的状况看,是不是发送速度过快导致接收那边卡住了,以至于没有返回信号,这个也好排查,你发送时候,加个延时,把发送频率降下来看看。

  1. 请确认单片机识别的结束位也同为'\r';
  2. if (mystring.Contains("ok"))这行代码可能有问题,因为串口是异步的,有可能发送太快造成收到的是"okokokokokokokok";
  3. "ok"字符串长度太短,用串口调试工具接收串口信息时经常发现有部分发送的信息没收到,但再发一个信息前面未收到的又出来了;
  4. 请确认串口接收未被以下代码阻塞没有执行。 while (send_rows > 30)//发送行数大于30行则停留在此循环 { System.Threading.Thread.Sleep(100);//延时0.1s }

终于找到原因了,串口有个属性触发接收数据门限,原来默认是8,返回值 ok\n 是3个字符,所以并不是每次返回值触发一次数据接收事件,
将改属性值改为3即可。

serialPort1.ReceivedBytesThreshold = 3