C# 串口读取数据不完整

时间:2022-08-02 02:10:37
int bytes = serialPort1.BytesToRead; 

我在后面定义一个数组:

 byte[] buffer = new byte[bytes];

当串口缓存里有16个数据时,bytes却只有3,有时是13,有时8,反正经常只读了一部分数据,导致该数组里的数据总是一经判断就出错。为什么呀?为何bytes和serialPort1.BytesToRead不相等,怎么解决这个问题,希望大家帮帮我! 

35 个解决方案

#1


先标记,等两天我也要用串口编程!

#2


为了积分,不好意思

#3


我一般都是先收下来之后,判断如果不对就存放在缓冲数组中,再下一次收取数据时拼接到缓冲数组后再进行判断。也就是不指望一次就能将数据收齐。

#4


等肯定是等的,不过有些串口要多发几个字节,调式一下吧 .

#5


先确定你的返回数据是多少字节,在接收之前定义一个字节数组,注意这个字节数组的长度一定要比接收的数据长。
例如:

                if (!serialPort1.IsOpen)
                {
                    serialPort1.Open();
                }
byte[] temp1 = mysendb("FF FF 00 00 FF FF"); //复位指令
serialPort1.Write(temp1, 0, 6);//发送复位数据
                 Thread.Sleep(1000);
                 byte[] recb = new byte[6];//接收复位返回值
                 int iffuwei = serialPort1.Read(recb, 0, 6);

#6


不懂,学习一下

#7


把代碼放線程或者計時器 里去循環接收


 if (AVR.BytesToRead > 0)
 {
     byte[] tmpbuf = new byte[AVR.BytesToRead];
     AVR.Read(tmpbuf, 0, AVR.BytesToRead);
     ls_RevceDate = BitConverter.ToString(tmpbuf).Trim();
                   
  }

#8


学习中。。。。

#9


循环read的话,会读多了,因为我接收的数据的一组一组地过来的,循环地读会读到下一组的数据。

#10


读多了没有什么关系啊,只要你的数据是有边界可以分割的就没有问题。

#11


我只需要读到一组的包尾就停止  

#12


for (;;)
            {
                serialPort1.Read(buffer, 0, bytes);
                if (buffer[bytes - 2] == 255 & buffer[bytes - 1] == 255)
                    break;
            }

这个循环读取 有问题吗

#13


基本常识,流设备是需要先缓存再分析的。

#14


把串口读出来的数据放入缓存,再从缓存读需要的数据进行分析?

#15


引用 9 楼 ac_lotus_g 的回复:
循环read的话,会读多了,因为我接收的数据的一组一组地过来的,循环地读会读到下一组的数据。

在没组数据后面加个标志  
在读取 判断标志 

#16


Application.Doevents();

#17



public partial class Form1 : Form
    {
        delegate void del();
        public Form1()
        {
            InitializeComponent();
        }

        private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            this.Invoke(new del(A));
        }
        private void A()
        {
            if (serialPort1.BytesToRead == 9)
            {
                byte[] buffer = new byte[serialPort1.BytesToRead];
                serialPort1.Read(buffer, 0, serialPort1.BytesToRead);
               string str=Encoding.ASCII.GetString(buffer);
                richTextBox1.AppendText(str);
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            serialPort1.Open();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (serialPort1.IsOpen)
            {
                serialPort1.Close();
            }
        }
    }

不知你具体的需求是什么,反正我能顺利将数据按9个字节读进来为。

#18


我每组数据的最后两个是255,大家帮我看看程序问题在哪儿?

             int bytes = serialPort1.BytesToRead;
            byte[] buffer = new byte[bytes];
            
            for (;;)
            {

                serialPort1.Read(buffer, 0, bytes);
                if (buffer[bytes - 2] == 255 & buffer[bytes - 1] == 255)
                    break;
            }

因为出现了只读取了一部分数据的情况,我加了for语句是想反复读数据,判断所读取的数据最后两个是255的时候,就认为已经完整读取了一组数据,跳出循环,往下执行。


感觉程序有问题,希望大家指点一下。 

#19


引用 17 楼 w_f_y4422 的回复:


我会收到一组一组的数据,完整地读出每一组数据并进行处理就是我的目的!为了避免冲突,下位机发上的每组数据之间会有两三秒的延迟。

#20


首先你要明白Read方法会导致BytesToRead重新计算,所以你的程序必定是有问题,其次if (buffer[bytes - 2] == 255 & buffer[bytes - 1] == 255)
里的&应该改为&&.
假如你的每组数据长度不固定,只是以255 作为结束标志,我觉得要另建一数组,每次读取一字节进去,遇到255时表示读完,取出这数组的值,然后清空,重新再填。

#21


试试这样子

List<byte> arr = new List<byte>();
            while (true)
            {
                if (serialPort1.BytesToRead > 0)
                {
                    arr.Add((byte)serialPort1.ReadByte());
                    if (arr.Count > 2)
                    {
                        int len = arr.Count;
                        if (arr[len - 1] == 255 && arr[len - 2] == 255)
                        {
                            break;
                        }
                    }
                }
            }
            /*
             * 处理arr

            */
            arr.Clear();

#22


  System.Threading.Thread.Sleep(500);//发送完信息立即接收一定要加上延时函数
不然肯定会接收不完整了

#23


也要看你的代码是什么时候执行的,如果放在串口接收事件里,根本不用循环,否则会死掉。

#24


引用 23 楼 w_f_y4422 的回复:
也要看你的代码是什么时候执行的,如果放在串口接收事件里,根本不用循环,否则会死掉。



就在   serialPort1_DataReceived_1()里啊

#25


那么就不要循环了,把21楼的循环去掉,
List<byte> arr = new List<byte>();放在外事件处理函数外面

#26


串口,波特率等是否可以保证正常??

#27


引用 25 楼 w_f_y4422 的回复:
那么就不要循环了,把21楼的循环去掉,
List<byte> arr = new List<byte>();放在外事件处理函数外面


我把数据读到list中后,再把list中的数据放到数组buffer里,把list清空,后面显示buffer里的数据
发到400多组的时候,又开始整组丢数据了。

代码如下:

 List<byte> arr = new List<byte>();
            while (true)
            {
                if (serialPort1.BytesToRead > 0)
                {
                    System.Threading.Thread.Sleep(10);
                    arr.Add((byte)serialPort1.ReadByte());
                    if (arr.Count > 2)
                    {
                        int len = arr.Count;
                        if (arr[len - 1] == 255 && arr[len - 2] == 255)
                        {
                            break;
                        }
                    }
                }
            }
            int bytes = arr.Count;
            byte[] buffer = new byte[bytes];

            for (int i = 0; i < bytes; i++)
            {
                buffer[i] = arr[i];

            }
            arr.Clear();

#28


引用 26 楼 lovesoftandhxy 的回复:
串口,波特率等是否可以保证正常??



正常啊!

#29


  serialPort1.ReadBufferSize 串口缓冲大小设了没

#30


不知道你的什么问题,我以前读取的PLC的串口数据包。
我觉得你直接判断报文结束字符不就行了

#31


引用 29 楼 ling3wei 的回复:
serialPort1.ReadBufferSize 串口缓冲大小设了没



readbuffersize 设了8192

#32


纯顶 学习下

#33


一个一个地读,读到包尾就停止,是可行的!

#34


学习之

#35


该回复于2011-04-26 08:49:16被版主删除

#1


先标记,等两天我也要用串口编程!

#2


为了积分,不好意思

#3


我一般都是先收下来之后,判断如果不对就存放在缓冲数组中,再下一次收取数据时拼接到缓冲数组后再进行判断。也就是不指望一次就能将数据收齐。

#4


等肯定是等的,不过有些串口要多发几个字节,调式一下吧 .

#5


先确定你的返回数据是多少字节,在接收之前定义一个字节数组,注意这个字节数组的长度一定要比接收的数据长。
例如:

                if (!serialPort1.IsOpen)
                {
                    serialPort1.Open();
                }
byte[] temp1 = mysendb("FF FF 00 00 FF FF"); //复位指令
serialPort1.Write(temp1, 0, 6);//发送复位数据
                 Thread.Sleep(1000);
                 byte[] recb = new byte[6];//接收复位返回值
                 int iffuwei = serialPort1.Read(recb, 0, 6);

#6


不懂,学习一下

#7


把代碼放線程或者計時器 里去循環接收


 if (AVR.BytesToRead > 0)
 {
     byte[] tmpbuf = new byte[AVR.BytesToRead];
     AVR.Read(tmpbuf, 0, AVR.BytesToRead);
     ls_RevceDate = BitConverter.ToString(tmpbuf).Trim();
                   
  }

#8


学习中。。。。

#9


循环read的话,会读多了,因为我接收的数据的一组一组地过来的,循环地读会读到下一组的数据。

#10


读多了没有什么关系啊,只要你的数据是有边界可以分割的就没有问题。

#11


我只需要读到一组的包尾就停止  

#12


for (;;)
            {
                serialPort1.Read(buffer, 0, bytes);
                if (buffer[bytes - 2] == 255 & buffer[bytes - 1] == 255)
                    break;
            }

这个循环读取 有问题吗

#13


基本常识,流设备是需要先缓存再分析的。

#14


把串口读出来的数据放入缓存,再从缓存读需要的数据进行分析?

#15


引用 9 楼 ac_lotus_g 的回复:
循环read的话,会读多了,因为我接收的数据的一组一组地过来的,循环地读会读到下一组的数据。

在没组数据后面加个标志  
在读取 判断标志 

#16


Application.Doevents();

#17



public partial class Form1 : Form
    {
        delegate void del();
        public Form1()
        {
            InitializeComponent();
        }

        private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            this.Invoke(new del(A));
        }
        private void A()
        {
            if (serialPort1.BytesToRead == 9)
            {
                byte[] buffer = new byte[serialPort1.BytesToRead];
                serialPort1.Read(buffer, 0, serialPort1.BytesToRead);
               string str=Encoding.ASCII.GetString(buffer);
                richTextBox1.AppendText(str);
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            serialPort1.Open();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (serialPort1.IsOpen)
            {
                serialPort1.Close();
            }
        }
    }

不知你具体的需求是什么,反正我能顺利将数据按9个字节读进来为。

#18


我每组数据的最后两个是255,大家帮我看看程序问题在哪儿?

             int bytes = serialPort1.BytesToRead;
            byte[] buffer = new byte[bytes];
            
            for (;;)
            {

                serialPort1.Read(buffer, 0, bytes);
                if (buffer[bytes - 2] == 255 & buffer[bytes - 1] == 255)
                    break;
            }

因为出现了只读取了一部分数据的情况,我加了for语句是想反复读数据,判断所读取的数据最后两个是255的时候,就认为已经完整读取了一组数据,跳出循环,往下执行。


感觉程序有问题,希望大家指点一下。 

#19


引用 17 楼 w_f_y4422 的回复:


我会收到一组一组的数据,完整地读出每一组数据并进行处理就是我的目的!为了避免冲突,下位机发上的每组数据之间会有两三秒的延迟。

#20


首先你要明白Read方法会导致BytesToRead重新计算,所以你的程序必定是有问题,其次if (buffer[bytes - 2] == 255 & buffer[bytes - 1] == 255)
里的&应该改为&&.
假如你的每组数据长度不固定,只是以255 作为结束标志,我觉得要另建一数组,每次读取一字节进去,遇到255时表示读完,取出这数组的值,然后清空,重新再填。

#21


试试这样子

List<byte> arr = new List<byte>();
            while (true)
            {
                if (serialPort1.BytesToRead > 0)
                {
                    arr.Add((byte)serialPort1.ReadByte());
                    if (arr.Count > 2)
                    {
                        int len = arr.Count;
                        if (arr[len - 1] == 255 && arr[len - 2] == 255)
                        {
                            break;
                        }
                    }
                }
            }
            /*
             * 处理arr

            */
            arr.Clear();

#22


  System.Threading.Thread.Sleep(500);//发送完信息立即接收一定要加上延时函数
不然肯定会接收不完整了

#23


也要看你的代码是什么时候执行的,如果放在串口接收事件里,根本不用循环,否则会死掉。

#24


引用 23 楼 w_f_y4422 的回复:
也要看你的代码是什么时候执行的,如果放在串口接收事件里,根本不用循环,否则会死掉。



就在   serialPort1_DataReceived_1()里啊

#25


那么就不要循环了,把21楼的循环去掉,
List<byte> arr = new List<byte>();放在外事件处理函数外面

#26


串口,波特率等是否可以保证正常??

#27


引用 25 楼 w_f_y4422 的回复:
那么就不要循环了,把21楼的循环去掉,
List<byte> arr = new List<byte>();放在外事件处理函数外面


我把数据读到list中后,再把list中的数据放到数组buffer里,把list清空,后面显示buffer里的数据
发到400多组的时候,又开始整组丢数据了。

代码如下:

 List<byte> arr = new List<byte>();
            while (true)
            {
                if (serialPort1.BytesToRead > 0)
                {
                    System.Threading.Thread.Sleep(10);
                    arr.Add((byte)serialPort1.ReadByte());
                    if (arr.Count > 2)
                    {
                        int len = arr.Count;
                        if (arr[len - 1] == 255 && arr[len - 2] == 255)
                        {
                            break;
                        }
                    }
                }
            }
            int bytes = arr.Count;
            byte[] buffer = new byte[bytes];

            for (int i = 0; i < bytes; i++)
            {
                buffer[i] = arr[i];

            }
            arr.Clear();

#28


引用 26 楼 lovesoftandhxy 的回复:
串口,波特率等是否可以保证正常??



正常啊!

#29


  serialPort1.ReadBufferSize 串口缓冲大小设了没

#30


不知道你的什么问题,我以前读取的PLC的串口数据包。
我觉得你直接判断报文结束字符不就行了

#31


引用 29 楼 ling3wei 的回复:
serialPort1.ReadBufferSize 串口缓冲大小设了没



readbuffersize 设了8192

#32


纯顶 学习下

#33


一个一个地读,读到包尾就停止,是可行的!

#34


学习之

#35


该回复于2011-04-26 08:49:16被版主删除