现在楼主接收的是后面的数据而前面的数据消失了,应该就是你在事件中处理数据过慢 导致新的串口数据往缓存区中发送把你原有缓存区的数据冲掉了。在接收事件中就不应该去做数据的处理特别是大循环的语句会消耗你机器的性能和时间,定义一个缓存区只做数据的接收,在另外开启一个线程来做数据的处理 ,比如你所需要的字符串的拼接。
而微软封装串行口的接收数据事件是另外开了一个异步线程来做的处理。
int data_num = 0;//上次未处理数据长度
byte[] data_buf = new byte[50000];//存放上次未处理数据
接收处理程序:
else
{
int _frame_num = 0; // 接收帧在frame数组里的索引,
int _frame_len = 0; // 帧长度 ,
if (n > 20000) return;//接收到的数据过长,可能出错
serialPort1.Read(data_buf, data_num, n);//读取缓冲数据,从data_buf的第data_num处开始写入,与之前未处理数据连接在一起
data_num += n;//未处理的数据位置 重新定位到 data_num + n
int I = 0;//
while (I < data_num - 4)//遍历接收数据
{
if (data_buf[I] == 0xaa && data_buf[I + 1] == 0xaa && data_buf[I + 3] < 51)
{
_frame_num = data_buf[I + 2];
_frame_len = data_buf[I + 3];
if ((data_num - I - 5) >= _frame_len) // 数据接收完毕
{
byte sum = 0;
for (int j = I; j <= I + 3 + _frame_len; j++)//计算sum
sum += data_buf[j];
if (sum == data_buf[I + 4 + _frame_len])//sum校验通过
{
int j;
switch (_frame_num)
{
case 2://传感器数据
j = I + 4;
S_acc_x = (Int16)(data_buf[j] << 8 | data_buf[j + 1]);
S_acc_y = (Int16)(data_buf[j + 2] << 8 | data_buf[j + 3]);
S_acc_z = (Int16)(data_buf[j + 4] << 8 | data_buf[j + 5]);
S_gyr_x = (Int16)(data_buf[j + 6] << 8 | data_buf[j + 7]);
S_gyr_y = (Int16)(data_buf[j + 8] << 8 | data_buf[j + 9]);
S_gyr_z = (Int16)(data_buf[j + 10] << 8 | data_buf[j + 11]);
S_mag_x = (Int16)(data_buf[j + 12] << 8 | data_buf[j + 13]);
S_mag_y = (Int16)(data_buf[j + 14] << 8 | data_buf[j + 15]);
S_mag_z = (Int16)(data_buf[j + 16] << 8 | data_buf[j + 17]);
break;
default:
break;
}
I = I + 5 + _frame_len; // I指向下一帧数据
}
else//sum校验未通过
{
I++;
}
}
else//HEAD FUN LEN符合要求,但是数据未接收完毕
{
for (int j = I; j <= data_num - 1; j++)
{
data_buf[j - I] = data_buf[j];
}
data_num = data_num - I;
return;
}
}
else//HEAD FUN LEN 不符合要求
{
I++;
}
}
if (I < data_num) // 剩几字节没有处理完
{
for (int j = I; j <= data_num - 1; j++)
{
data_buf[j - I] = data_buf[j];
}
data_num = data_num - I;
}
}
}
使 用缓存机制完成。首先通过定义一个成员变量List<byte> buffer = new List<byte> (4096);用来存放所有的数据,在接收函数里,通过buffer.AddRange()方法不断地将接收到的数据加入到buffer中,并同时对 buffer中的数据进行检验,如果达到一定的长度并且校验结果正确(校验方法在发送方和接收方一致),再进行处理。具体代码如下:代码
private List<byte> buffer = new List<byte>(4096);
private void sp_DataReceived(objectsender, EventArgs e) //sp是串口控件
{
int n = sp.BytesToRead;
byte[] buf = new byte[n];
sp.Read(buf, 0, n);
//1.缓存数据
buffer.AddRange(buf);
//2.完整性判断
while (buffer.Count >= 4) //至少包含帧头(2字节)、长度(1字节)、校验位(1字节);根据设计不同而不同
{
//2.1 查找数据头
if (buffer[0] == 0x01) //传输数据有帧头,用于判断
{
int len = buffer[2];
if (buffer.Count < len + 4) //数据区尚未接收完整
{
break;
}
//得到完整的数据,复制到ReceiveBytes中进行校验
buffer.CopyTo(0, ReceiveBytes, 0, len + 4);
byte jiaoyan; //开始校验
jiaoyan = this.JY(ReceiveBytes);
if (jiaoyan != ReceiveBytes[len+3]) //校验失败,最后一个字节是校验位
{
buffer.RemoveRange(0, len + 4);
MessageBox.Show("数据包不正确!");
continue;
}
buffer.RemoveRange(0, len + 4);
/////执行其他代码,对数据进行处理。
}
else //帧头不正确时,记得清除
{
buffer.RemoveAt(0);
}
}
}
发现自己的不足,善于利用找到的方法去扬长避短。行动起来。