我采用的是SerialPort类的DateReceived方法接收数据,思路是:先将数值转化为字节发送到串口接收端,之后根据接收端的字节转为数据。具体代码如下:
初始化:
int x1=0; int x2=0;...........................int x100=0;
定义数据字节转换类:
public class SetParameter
{
这里主要定义字节和数据的转换,例如 : A的攻击力:100
发送时将100转化成十六进制,根据要求 结果是 88 01 00 64 65
然后接收数据时根据上面的字节存入ListBox1中显示正确的数据
}
发送所有数据按钮:(可能这里的Thread.sleep()有问题)
progressBar1.Value = 0;
for (listBox1.SelectedIndex = 0; listBox1.SelectedIndex <= 100; listBox1.SelectedIndex++)
{
SetParameter sp = new SetParameter();//设置参数
double p0 = 0;//将具体的参数赋值给p0
int n = listBox1.SelectedIndex;//ListBox1的选中行位置,后面主要把位置转化为序号
string p1 = sp.SetP1();//定义字节1
string p2 = sp.SetP2(n);//定义字节2(序号)
#region 代入ListBox1的参数值
switch (n)
{
case 1:
{
p0 = x1;
break;
}
..........................................................
case 100:
{
p0 = x100;
break;
}
}
#endregion
double x = sp.Parameters(p0, p2);
string p3 = sp.SetP3(x);//定义字节3
string p4 = sp.SetP4(x);//定义字节4
string p5 = sp.SetP5(n, x);//定义字节5
/*发送数据开始*/
serialPort1.Write(p1);
progressBar1.Value += progressBar1.Step;
Thread.Sleep(20);
serialPort1.Write(p2);
progressBar1.Value += progressBar1.Step;
Thread.Sleep(20);
serialPort1.Write(p3);
progressBar1.Value += progressBar1.Step;
Thread.Sleep(20);
serialPort1.Write(p4);
progressBar1.Value += progressBar1.Step;
Thread.Sleep(20);
serialPort1.Write(p5);
progressBar1.Value += progressBar1.Step;
Thread.Sleep(50);
}
接收数据 :
为了方便查看,我创建了一个文本框 名称为 richReceiveText1
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (Closing) return;//如果正在关闭,忽略操作,直接返回,尽快的完成串口监听线程的一次循环
try
{
int len = serialPort1.BytesToRead;//定义字节数组的长度:每接收一次数据读取的字符串长度
Byte[] bytes = new Byte[len];//建立字节数组对象
serialPort1.Read(bytes, 0, len);//读取接收的字节
builder.Clear();//接收数据时清除之前的残余字符串
//定义异步线程判断字符串的内容
this.Invoke((EventHandler)delegate
{
builder.Append(Encoding.ASCII.GetString(bytes));
richReceiveText1.AppendText(builder.ToString().Replace(" ", ""));
int d1 = Convert.ToInt32(richReceiveText1.Text.Substring(0, 2), 16);
if (d1 == 136 && richReceiveText1.Text.Length == 10)
{
int d2 = Convert.ToInt32(richReceiveText1.Text.Substring(2, 2), 10);
int d3 = Convert.ToInt32(richReceiveText1.Text.Substring(4, 2), 16);
int d4 = Convert.ToInt32(richReceiveText1.Text.Substring(6, 2), 16);
int d5 = Convert.ToInt32(richReceiveText1.Text.Substring(8, 2), 16);
if (1 <= d2 && d2 <= 96)
{
#region 字节转为数据
switch (d2)
{
case 1:
{
x1 = (d4 * 256 + d3) / 32; listBox1.Items[1] = " A的攻击力:" + x1;
richReceiveText1.Clear(); listBox1.SelectedIndex = 1;
break;
}
......................................
case 96:
{
aux_cont_vol = (d4 * 256 + d3) / 64; listBox1.SelectedIndex = 110;
listBox1.Items[110] = "Z的魔法攻击必杀率:" + x110 + "%"; richReceiveText1.Clear();
break;
}
}
#endregion
}
}
});
}finally
{
Listening = false;
}
}
但问题出现了:
问题1:
当listBox1的高度设置的很大,看不到垂直滚动栏时,数据都可以完美接收
但是listBox1的高度不太高时,每次移动到当前屏幕最低端的时候(比如listbox1.selectedindex=35)数据就接收失败
失败的现象就是listBox1显示到那行时,richReceiveText1的内容不会想往常那样清空,从而ListBox1收不到数据。
但我把Thread.sleep的参数定义到100以上时,此问题的出现率会减少很多,但我们要求是20ms间隔。
问题2:
我把DataReceive方法绑定到一个按钮里了,当这个按钮没开,发送端发送数据时,正常没数据。但再次发送数据时,之前全部发送的数据的十六进制都会在richReceiveText1里出现。
希望大神们帮忙看哪里有问题呢?求助~~谢谢。如果有需要贴出其他代码可以贴
------解决思路----------------------
网络通信就是这样子的,收发不是一一对应的,
可能一次收到多个包,也可能多次才收全一个包。
不是定长的包,就得加包头,说明包长度。最好再加包尾验证。