本人用C#刚接触串口通信不久,在网上找了一些串口通信的资料,按照资料中的讲解做了个串口通信程序,但是在和下位机通信的时候接收到的数据总是不对,不知道是什么原因,哪位懂C#串口通信的大侠能指点下吗?
正确的数据格式应该是这样的:F0 55 AA 04 07 0D 01 00 02 00 03 00 04 0D 00 0F 00 13 00 04 00 14 00 98 00 03 00 0B 00 83 00 7C 00 07 00 7F 00 80 00 88 9C 9C 但是不知道为什么我用程序中的代码接收到的数据格式却是这样的:AA AA 00 00 00 00 00 00 00 AA AA 04 04 04 0F 00 00 00 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 。哪位大侠能告诉我问题出在哪里吗?
下面是我的发送程序的代码:
//处理数字转换,目的是将输入的字符按空格、“,”等分组,以便发送数据时的方便(此处转的比较麻烦,有高见者,请指点!)
comm.RtsEnable = true;
//comm.Parity = Parity.Mark;
Thread.Sleep(2);
// comm.Parity = Parity.Mark;
byte[] byteBuffer2 = new byte[9];
byteBuffer2[0] = 0xaa;
byteBuffer2[1] = 0xaa;
byteBuffer2[2] = 0x04;
byteBuffer2[3] = 0x04;
byteBuffer2[4] = 0x04;
byteBuffer2[5] = 0x0f;
byteBuffer2[6] = 0x00;
byteBuffer2[7] = 0x00;
byteBuffer2[8] = 0x00;
String strSend2 = byteBuffer2[0].ToString("X2") + " " + byteBuffer2[1].ToString("X2") + " " + byteBuffer2[2].ToString("X2") + " " + byteBuffer2[3].ToString("X2") + " " + byteBuffer2[4].ToString("X2") + " " +
byteBuffer2[5].ToString("X2") + " " + byteBuffer2[6].ToString("X2") + " " + byteBuffer2[7].ToString("X2") + " " + byteBuffer2[8].ToString("X2");
string sendBuf2 = strSend2;
string sendnoNull2 = sendBuf2.Trim();
string sendNOComma6 = sendnoNull2.Replace(',', ' '); //去掉英文逗号
string sendNOComma7 = sendNOComma6.Replace(',', ' '); //去掉中文逗号
string strSendNoComma8 = sendNOComma7.Replace("0x", ""); //去掉0x
strSendNoComma8.Replace("0X", ""); //去掉0X
string[] strArray2 = strSendNoComma8.Split(' '); List<byte> buf2 = new List<byte>();//填充到这个临时列表中
//依次添加到列表中
int byteBufferLength2 = strArray2.Length;
for (int i = 0; i < strArray2.Length; i++)
{
byte str2 = byte.Parse(strArray2[i].ToString(), System.Globalization.NumberStyles.HexNumber);
buf2.Add(str2);
}
//转换列表为数组后发送
comm.Write(buf2.ToArray(), 0, buf2.Count);
Thread.Sleep(60); comm.RtsEnable = false;
//Thread.Sleep(16);
comm.Parity = Parity.Mark;接收部分的代码如下
void comm_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//更新界面
//this.Invoke((EventHandler)(delegate { richTextBox1.Text = ""; }));
//buffer.RemoveAt(0);
Thread.Sleep(500);//此处一定要有,休眠一段 时间利用缓存来接收数据,经测试75秒刚好
if (Closing) return;//如果正在关闭,忽略操作,直接返回,尽快的完成串口监听线程的一次循环
try
{
Listening = true;//设置标记,说明我已经开始处理数据,一会儿要使用系统UI的。
int n = comm.BytesToRead;//先记录下来,避免某种原因,人为的原因,操作几次之间时间长,缓存不一致
byte[] buf = new byte[n];//声明一个临时数组存储当前来的串口数据
received_count = n;//增加接收计数
//richTextBox3.Text = received_count.ToString();
//MessageBox.Show(received_count.ToString());
comm.Read(buf, 0, n);//读取缓冲数据
builder.Length=0;//清除字符串构造器的内容 //<协议解析>
bool data_1_catched = false;//缓存记录数据是否捕获到
buffer.AddRange(buf);
if (buffer.Count >=9)
{
string data,data1;
data = "";
data1 = "";
//MessageBox.Show(buf[8].ToString("X2"));
for (int i = 0; i < n; i++)
{
data1 += buffer[i].ToString("X2") + " ";
data += buf[i].ToString("X2") + " ";
// data = n.ToString();
}
//更新界面
this.Invoke((EventHandler)(delegate { richTextBox4.Text = data; }));
this.Invoke((EventHandler)(delegate { richTextBox3.Text = data; }));
//因为要访问ui资源,所以需要使用invoke方式同步ui。
this.Invoke((EventHandler)(delegate
{
//判断是否是显示为16禁止
if (checkBox3.Checked)
{
//依次的拼接出16进制字符串
foreach (byte b in buf)
{
builder.Append(b.ToString("X2") + " ");
}
}
else
{
//直接按ASCII规则转换成字符串
builder.Append(Encoding.ASCII.GetString(buf));
}
//追加的形式添加到文本框末端,并滚动到最后。
richTextBox1.AppendText(builder.ToString());
// richTextBox1.Text=builder.ToString();
//修改接收计数
//labelGetCount.Text = "Get:" + received_count.ToString();
}));
}
}
finally
{
Listening = false;//我用完了,ui可以关闭串口了。
} }
正确的数据格式应该是这样的:F0 55 AA 04 07 0D 01 00 02 00 03 00 04 0D 00 0F 00 13 00 04 00 14 00 98 00 03 00 0B 00 83 00 7C 00 07 00 7F 00 80 00 88 9C 9C 但是不知道为什么我用程序中的代码接收到的数据格式却是这样的:AA AA 00 00 00 00 00 00 00 AA AA 04 04 04 0F 00 00 00 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 。哪位大侠能告诉我问题出在哪里吗?
下面是我的发送程序的代码:
//处理数字转换,目的是将输入的字符按空格、“,”等分组,以便发送数据时的方便(此处转的比较麻烦,有高见者,请指点!)
comm.RtsEnable = true;
//comm.Parity = Parity.Mark;
Thread.Sleep(2);
// comm.Parity = Parity.Mark;
byte[] byteBuffer2 = new byte[9];
byteBuffer2[0] = 0xaa;
byteBuffer2[1] = 0xaa;
byteBuffer2[2] = 0x04;
byteBuffer2[3] = 0x04;
byteBuffer2[4] = 0x04;
byteBuffer2[5] = 0x0f;
byteBuffer2[6] = 0x00;
byteBuffer2[7] = 0x00;
byteBuffer2[8] = 0x00;
String strSend2 = byteBuffer2[0].ToString("X2") + " " + byteBuffer2[1].ToString("X2") + " " + byteBuffer2[2].ToString("X2") + " " + byteBuffer2[3].ToString("X2") + " " + byteBuffer2[4].ToString("X2") + " " +
byteBuffer2[5].ToString("X2") + " " + byteBuffer2[6].ToString("X2") + " " + byteBuffer2[7].ToString("X2") + " " + byteBuffer2[8].ToString("X2");
string sendBuf2 = strSend2;
string sendnoNull2 = sendBuf2.Trim();
string sendNOComma6 = sendnoNull2.Replace(',', ' '); //去掉英文逗号
string sendNOComma7 = sendNOComma6.Replace(',', ' '); //去掉中文逗号
string strSendNoComma8 = sendNOComma7.Replace("0x", ""); //去掉0x
strSendNoComma8.Replace("0X", ""); //去掉0X
string[] strArray2 = strSendNoComma8.Split(' '); List<byte> buf2 = new List<byte>();//填充到这个临时列表中
//依次添加到列表中
int byteBufferLength2 = strArray2.Length;
for (int i = 0; i < strArray2.Length; i++)
{
byte str2 = byte.Parse(strArray2[i].ToString(), System.Globalization.NumberStyles.HexNumber);
buf2.Add(str2);
}
//转换列表为数组后发送
comm.Write(buf2.ToArray(), 0, buf2.Count);
Thread.Sleep(60); comm.RtsEnable = false;
//Thread.Sleep(16);
comm.Parity = Parity.Mark;接收部分的代码如下
void comm_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//更新界面
//this.Invoke((EventHandler)(delegate { richTextBox1.Text = ""; }));
//buffer.RemoveAt(0);
Thread.Sleep(500);//此处一定要有,休眠一段 时间利用缓存来接收数据,经测试75秒刚好
if (Closing) return;//如果正在关闭,忽略操作,直接返回,尽快的完成串口监听线程的一次循环
try
{
Listening = true;//设置标记,说明我已经开始处理数据,一会儿要使用系统UI的。
int n = comm.BytesToRead;//先记录下来,避免某种原因,人为的原因,操作几次之间时间长,缓存不一致
byte[] buf = new byte[n];//声明一个临时数组存储当前来的串口数据
received_count = n;//增加接收计数
//richTextBox3.Text = received_count.ToString();
//MessageBox.Show(received_count.ToString());
comm.Read(buf, 0, n);//读取缓冲数据
builder.Length=0;//清除字符串构造器的内容 //<协议解析>
bool data_1_catched = false;//缓存记录数据是否捕获到
buffer.AddRange(buf);
if (buffer.Count >=9)
{
string data,data1;
data = "";
data1 = "";
//MessageBox.Show(buf[8].ToString("X2"));
for (int i = 0; i < n; i++)
{
data1 += buffer[i].ToString("X2") + " ";
data += buf[i].ToString("X2") + " ";
// data = n.ToString();
}
//更新界面
this.Invoke((EventHandler)(delegate { richTextBox4.Text = data; }));
this.Invoke((EventHandler)(delegate { richTextBox3.Text = data; }));
//因为要访问ui资源,所以需要使用invoke方式同步ui。
this.Invoke((EventHandler)(delegate
{
//判断是否是显示为16禁止
if (checkBox3.Checked)
{
//依次的拼接出16进制字符串
foreach (byte b in buf)
{
builder.Append(b.ToString("X2") + " ");
}
}
else
{
//直接按ASCII规则转换成字符串
builder.Append(Encoding.ASCII.GetString(buf));
}
//追加的形式添加到文本框末端,并滚动到最后。
richTextBox1.AppendText(builder.ToString());
// richTextBox1.Text=builder.ToString();
//修改接收计数
//labelGetCount.Text = "Get:" + received_count.ToString();
}));
}
}
finally
{
Listening = false;//我用完了,ui可以关闭串口了。
} }
解决方案 »
- C#中怎么连接sybase iq数据库做操作?
- 急求... C# 穿越 NAT UDP 的 方法... 最好 有源代码... 非常感谢!~
- Http的Post、Get方法上报和下载以XML格式的数据如何实现?
- 如何改变生成的xml的编码方式.
- 又来麻烦各位了
- 不同数据库之间数据的转移问题
- ******请问,这个功能如何实现???*******
- 请大家告诉我如何把做好的程序移植到其他机器上,并使之正常运行
- 使用ReportViewer显示报表XP环境下一刷新程序会自动奔溃退出无异常提示
- Winfrom下的Chart控件如何加载?VS2010 .NetFramework 4.0
- |ZYCWPF| 为RichTextBox添加查找替换功能,已经能够CTRL_F出查询窗口_但CTRL_H和F3没有办法绑定
- VS2010出现问题了,大神给解决下
那么多3F可能是由于发送了ASCII码以外的字符,但是却是以ASCII码的形式发送的,导致编码为“?”,对应ASCII值为3F
private void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
string s100 = "";
System.Threading.Thread.Sleep(100);
int bytes = serialPort.BytesToRead;
byte[] buffer = new byte[bytes];
if (bytes == 0)
{ return; }
serialPort.Read(buffer, 0, bytes);
s100 = ww(buffer);//字节数组转为十六进制字符串
if (s100 != "")
{ string s = "";
int length = Convert.ToInt32( buffer[7].ToString()) - 1;
for (int j = 9; j < length+9; j++)
{
string a= Convert.ToString(buffer[j],16);
if(a.Length==1)
{
a = "0" + a;
}
s += a;
}
//s = "";
// MessageBox.Show(s100);
aa = s100;
InvokeHelper.Set(richTextBox2, "Text", aa);
}
serialPort.DiscardInBuffer(); } public string ww(byte[] data)//字节数组转为十六进制字符串
{
StringBuilder sb = new StringBuilder(data.Length * 3);
foreach (byte b in data)
sb.Append(Convert.ToString(b, 16).PadLeft(2, '0').PadRight(3, ' '));
return sb.ToString().ToUpper();
}
byte[] buf = new byte[n];//声明一个临时数组存储当前来的串口数据
received_count = n;//增加接收计数
comm.Read(buf, 0, n);//读取缓冲数据
comm.Read(buf, 0, n);这样读取的话,接收到的什么,读取的就是什么呀,直接看buf里的是什么数据不就完事了吗,别老是怀疑这怀疑那的,你读取的方法没问题,找找下位机的问题吧
for (int i = 0; i < strX.Length; i = i + 2)
{
SendDataList.Add(strX.Substring(i, 2));//切割成两两一组的字符串
}
byte[] SendBytes = new byte[SendDataList.Count];
for (int j = 0; j < SendBytes.Length; j++)//遍历临时HEX字符串数组,存入byte数组
{
SendBytes[j] = (byte)(Convert.ToInt32(SendDataList[j], 16));
}
comm.Write(SendBytes, 0, SendBytes.Length);
这是其中的一部分,这是十六进制的形式读取
你可以用这个测试一下:你用两个com,中间接个转接线。COM1发送,COM2接受。看看发过去之后,回来的是不是原来的(自己发自己收)如果不是,很有可能是usb转串口线不稳定造成的。原来我也遇见过这个问题。建议用原生串口
也许问题根本就不是你接收的数据,是下位机发送的根本就是3F,那你不管怎么接受都是3F的。找找下位机的问题。你说解析出错,有什么好出错的,SerialPort.Read(byte[],int inbuffer,int count),按照这种办法读取缓冲区的数据,串口总线上的数据是什么,读到的就是什么,压根就不是你说的解析的不对。因为这种办法读取串口,是按照十六进制读取的,没有经过任何编码。
不要只在PC机上找问题,找找下位机的问题。如果PC机读取没有问题,你就是找死了也找不到
private void button1_Click(object sender, EventArgs e)
{
int n = 0;
comm.Encoding = System.Text.Encoding.Unicode;
//16进制发送
if (checkBox1.Checked)
{
//处理数字转换,目的是将输入的字符按空格、“,”等分组,以便发送数据时的方便(此处转的比较麻烦,有高见者,请指点!)
comm.RtsEnable = true;
Thread.Sleep(2);
comm.Parity = Parity.Mark; //转换列表为数组后发送
byte[] send1 = { 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
comm.Write(send1, 0, send1.Length);
Thread.Sleep(50); comm.RtsEnable = false;
Thread.Sleep(2);
comm.Parity = Parity.Mark;
//处理数字转换,目的是将输入的字符按空格、“,”等分组,以便发送数据时的方便(此处转的比较麻烦,有高见者,请指点!)
comm.RtsEnable = true;
Thread.Sleep(2);
comm.Parity = Parity.Mark; //转换列表为数组后发送
byte[] send2 = { 0xaa, 0xaa, 0x01, 0x01, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00 };
comm.Write(send2, 0, send2.Length);
Thread.Sleep(50);
comm.RtsEnable = false;
Thread.Sleep(10); comm.Parity = Parity.Mark;
}
else//ascii编码直接发送
{
//包含换行符
if (checkBox2.Checked)
{
comm.WriteLine(richTextBox2.Text);
// n = txSend.Text.Length + 2;
}
else//不包含换行符
{
comm.Write(richTextBox2.Text);
//n = txSend.Text.Length;
}
}
}
下面是我的接收代码
void comm_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
comm.Parity = Parity.Mark;
comm = (SerialPort)sender;
string s100 = "";
Thread.Sleep(500);//此处一定要有,休眠一段 时间利用缓存来接收数据,经测试75秒刚好
if (Closing) return;//如果正在关闭,忽略操作,直接返回,尽快的完成串口监听线程的一次循环
try
{
Listening = true;//设置标记,说明我已经开始处理数据,一会儿要使用系统UI的。 int n = comm.BytesToRead;//先记录下来,避免某种原因,人为的原因,操作几次之间时间长,缓存不一致
byte[] buf = new byte[n];//声明一个临时数组存储当前来的串口数据
received_count = n;//增加接收计数
builder.Length=0;//清除字符串构造器的内容 //<协议解析>
bool data_1_catched = false;//缓存记录数据是否捕获到
buffer.AddRange(buf);
if (buffer.Count >=9)
{
string data,data1;
data = "";
data1 = "";
//MessageBox.Show(buf[8].ToString("X2"));
for (int i = 0; i < n; i++)
{
data1 += Convert.ToString(buf[i],16);
data += buf[i].ToString("X2") + " ";
// data = n.ToString();
}
//更新界面
this.Invoke((EventHandler)(delegate { richTextBox4.Text = data; }));
this.Invoke((EventHandler)(delegate { richTextBox3.Text = data; }));
//因为要访问ui资源,所以需要使用invoke方式同步ui。
this.Invoke((EventHandler)(delegate
{
//判断是否是显示为16禁止
if (checkBox3.Checked)
{
//依次的拼接出16进制字符串
foreach (byte b in buf)
{
builder.Append(b.ToString("X2") + " ");
}
}
else
{
//直接按ASCII规则转换成字符串
builder.Append(Encoding.ASCII.GetString(buf));
}
//追加的形式添加到文本框末端,并滚动到最后。
richTextBox1.AppendText(builder.ToString());
comm.DiscardInBuffer();
}));
}
}
finally
{
Listening = false;//我用完了,ui可以关闭串口了。
} }
//转换列表为数组后发送
通讯协议是这样的:软件先向下位机下发0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 这几个数据,说明我要开始下发数据了,然后再下发0xaa, 0xaa, 0x01, 0x01, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00说明这是我下发的指令,下位机接收到了0xaa, 0xaa, 0x01, 0x01, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00指令以后会回传数据,
byte[] buf = new byte[n];//声明一个临时数组存储当前来的串口数据
received_count = n;//增加接收计数
builder.Length=0;//清除字符串构造器的内容
//<协议解析>
bool data_1_catched = false;//缓存记录数据是否捕获到
buffer.AddRange(buf);
int n = comm.BytesToRead;
byte[] buf = new byte[n];
received_count = n;//增加接收计数
comm.Read(buf, 0, n);//读取缓冲数据
你的3F是在哪里出现的?这是重点呀,是显示的时候?
comm.Read(buf, 0, n);在这设置一个断点,然后用监视窗口查看buf里的数据
我的方法是抛弃硬件的啊。你测试方法中怎么还包含硬件呢。我觉得,如果想排除软件问题,你就软件连接com1,串口助手连接com2 com1,2之间用交叉线连起来。如果软件发送 aaa,串口助手监听到aaa,说明发送没问题。如果串口助手发送bbb,软件收到bbb,则说明软件接受没问题。好了,剩下的八成是你硬件问题了。
你按照39楼的办法调试下,用串口助手发送消息给你的软件,看是不是能正确接收。然后再用你的软件发送消息给串口助手,看是不是能正常发送。
软件的波特率以及Parity的设置跟单片机一样吗?
另外,你说的串口服务器是什么?
using System.IO.Ports;namespace serialPortExample
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
} private void button1_Click(object sender, EventArgs e)
{
if (button1.Text == "打开串口")
{
button1.Text = "关闭串口";
serialPort1.Open();
}
else
{
button1.Text = "打开串口";
serialPort1.Close();
} } private void button3_Click(object sender, EventArgs e)
{
if (checkBox2.Checked)
{
string[]sentstring = textBox2.Text.Split(' ');
byte[] sendByte = new byte[sentstring.Length];
for (int i = 0; i < sentstring.Length; i++)
{
sendByte[i] = Convert.ToByte(sentstring[i],16);
}
serialPort1.Write(sendByte, 0, sendByte.Length);
}
else
{
string sentstring = textBox2.Text; serialPort1.Write(sentstring);
}
}
delegate void delegate1();
string s;
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
if (checkBox1.Checked)
{
byte[] tempDate = new byte[serialPort1.BytesToRead];
int length = serialPort1.Read(tempDate, 0, serialPort1.BytesToRead);
delegate1 receivedelegate1 = new delegate1(datareceive);
for (int i = 0; i < length; i++)
{
s += Convert.ToString(tempDate[i], 16)+" ";
} this.Invoke(receivedelegate1);
} else
{ delegate1 receivedelegate2 = new delegate1(datareceive); s += serialPort1.ReadExisting();
this.textBox1.Invoke(receivedelegate2);
/*new MethodInvoker//这是直接调用MethodInvoker委托
(
这是匿名委托
delegate
{
this.textBox1.AppendText(serialreadstring);
}
)*/ } }
public void datareceive()
{
//this.textBox1.AppendText(serialreadstring);
this.textBox1.Text += s;
}
private void button2_Click(object sender, EventArgs e)
{
textBox1.Clear();
} private void checkBox3_CheckedChanged(object sender, EventArgs e)
{
if (checkBox3.Checked)
{
timer1.Interval = Convert.ToInt32(textBox3.Text);
timer1.Enabled = true;
}
else
timer1.Enabled = false;
} private void timer1_Tick(object sender, EventArgs e)
{
button3_Click(null, null);
}
}
}
你的下位机对数据进行了处理,也许是按照TCP/IP协议,通过你的串口服务器可以还原真实数据。但是通过串口转换器得到的数据只是下位机经过处理后的。
你的这个串口服务器是和单片机一起提供的吗?这两个是由同个厂商提供的?
楼主是不是想以后不买串口服务器就可以直接从单片机接收数据呀
原来是我们的该死的下位机程序在那做怪,发现我们的下位机是这样设置的:串口程序在向下位机下发数据之前要先设置为MARK验证,数据发送完以后在接收的时候要设置为NONE验证,真是坑人啊!还好,终于把问题解决了,哈哈,今天心情真是好啊