c#中,确保数据接收完整的 串口处理程序:
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) { /* int n = comm.BytesToRead;//先记录下来,避免某种原因,人为的原因,操作几次之间时间长,缓存不一致 byte[] buf = new byte[n];//声明一个临时数组存储当前来的串口数据 received_count += n;//增加接收计数 comm.Read(buf, 0, n);//读取缓冲数据 builder.Clear();//清除字符串构造器的内容 //因为要访问ui资源,所以需要使用invoke方式同步ui。 this.Invoke((EventHandler)(delegate { //判断是否是显示为16禁止 if (checkBoxHexView.Checked) { //依次的拼接出16进制字符串 foreach (byte b in buf) { builder.Append(b.ToString("X2") + " "); } } else { //直接按ASCII规则转换成字符串 builder.Append(Encoding.ASCII.GetString(buf)); } //追加的形式添加到文本框末端,并滚动到最后。 * * //要解析字符串,根据长度定位,根据特殊字符定位,来解析数据。(还是要确保一个完整的数据包接收完整,并处理完整) * this.txGet.AppendText(builder.ToString()); //修改接收计数 labelGetCount.Text = "Get:" + received_count.ToString(); })); */ int n = serialPort1.BytesToRead;//待读字节个数 byte[] buf = new byte[n];//创建n个字节的缓存 serialPort1.Read(buf, 0, n);//读到在数据存储到buf //1.缓存数据 buffer.AddRange(buf);//不断地将接收到的数据加入到buffer链表中 //2.完整性判断 while (buffer.Count >= 4) //至少包含帧头(2字节)、长度(1字节)、功能位(1字节);根据设计不同而不同 { //2.1 查找数据头 if (buffer[0] == 0x0AA) //传输数据有帧头,用于判断. 找到帧头 AA AA 0A { int len = buffer[2]; //int len = 79; if (buffer.Count < len + 4) //数据区尚未接收完整, { break;//跳出接收函数后之后继续接收数据 } //得到完整的数据,复制到ReceiveBytes中进行校验 buffer.CopyTo(0, ReceiveBytes, 0, len + 4);// byte jiaoyan; //开始校验 jiaoyan = 0x01;//jiaoyan = this.JY(ReceiveBytes); if (jiaoyan != ReceiveBytes[3]) //验证功能位失败 if (jiaoyan != ReceiveBytes[len+3]) { buffer.RemoveRange(0, len + 4);//从链表中移除接收到的校验失败的数据, //MessageBox.Show("数据包不正确!");//显示数据包不正确, continue;//继续执行while循环程序, } buffer.RemoveRange(0, len + 4); //执行其他代码,对数据进行处理。 //解析5 6, 7 8字节的经纬度. DataProgress(); } else //帧头不正确时,记得清除 { buffer.RemoveAt(0);//清除第一个字节,继续检测下一个。 } } }
对串口而言,不存在完整数据长度,都是以Byte为单位;一般来说,通常是透过时间跟固定数量来进行接收动作。(可能要看各PC的OS或Driver的设置情况)
通常在串口处理上,要确认接收数据完整,是在PC软件上进行接收、保存跟判断的动作,在完整收到後,才进行显示或处理。
我现在的处理方法是根据串口接收事件的实际效果来的:接收的数量到达了一个数量后,我才开始处理,这样比原来的简单的判断效果好多了。
private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) { try { int byteNumber = SerialPort.BytesToRead; Common.Delay(20); //延时等待数据接收完毕。 while ((byteNumber < SerialPort.BytesToRead) && (SerialPort.BytesToRead < 4800)) { byteNumber = SerialPort.BytesToRead; Common.Delay(20); } int n = SerialPort.BytesToRead; //记录下缓冲区的字节个数 byte[] buf = new byte[n]; //声明一个临时数组存储当前来的串口数据 SerialPort.Read(buf, 0, n); //读取缓冲数据到buf中,同时将这串数据从缓冲区移除 //设置文字显示 Control.CheckForIllegalCrossThreadCalls = false; StringBuilder sb = new StringBuilder(); for (int i = 0; i < n; i++) { string s; if (buf[i] < 16) s = "0" + Convert.ToString(buf[i], 16).ToUpper() + " "; else s = Convert.ToString(buf[i], 16).ToUpper() + " "; sb.Append(s); } textBox1.Text = sb.ToString(); } catch (Exception ee) { } }
原文:http://www.cnblogs.com/rechen/p/5126278.html