C#串口接收数据丢失,最大只能收8个字节

wjh19900506 2015-04-11 06:30:23
不知道为什么,我和单片机做通信,发送01 03 00 00 00 04 44 09 正确回复应该是01 03 08 XX XX XX XX XX XX XX XX XX XX
但是只回复了01 03 08 XX XX XX XX XX,丢失了几个字节,而缓冲区的length做断点的时候不能超过8。。。有点郁闷,我的接收缓冲区最大是2048的。新手 求解答,谢谢!
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;

namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
int length,count; //缓冲区数据的字节数
byte[] rebuff=new byte[15];
byte[] returndata = new byte[2];
string data;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
int a;
for (a = 1; a < 11; a++)
{
comboBox1.Items.Add("COM"+a.ToString());
}
comboBox1.Text = "COM1";
}
private void button2_Click(object sender, EventArgs e)
{
try
{
serialPort1.PortName = comboBox1.Text; //串口
serialPort1.DataBits = 8; //数据位
serialPort1.StopBits = StopBits.One; //停止位
serialPort1.BaudRate = 9600; //波特率
serialPort1.Parity = Parity.Even; //偶校验
serialPort1.Open(); //打开串口
timer1.Start(); //启动定时器
ovalShape1.FillColor = Color.Red;
}
catch
{
ovalShape1.FillColor = Color.White;
MessageBox.Show("端口错误", "error");
serialPort1.Close();
}
}
public void senddata() //发送数据
{
try
{
byte[] buff = new byte[13];
buff[0] = 0x01;
buff[1] = 0x03;
buff[2] = 0x00;
buff[3] = 0x00;
buff[4] = 0x00;
buff[5] = 0x01;
crc16(buff,6);
buff[6] = returndata[0];
buff[7] = returndata[1];
serialPort1.Write(buff, 0, 8);
System.Threading.Thread.Sleep(100);
}
catch
{
MessageBox.Show("数据写入错误","error");
}
}
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e) //触发事件接收数据
{
System.Threading.Thread.Sleep(300); //延时
length = serialPort1.BytesToRead; //获取缓冲区字节数
serialPort1.Read(rebuff, 0, length); //读数据
this.Invoke(new EventHandler(display));
}
private void display(object sender, EventArgs e)
{
int i;
string str;
string[] data = new string[length];
for (i = 0; i < length; i++)
{
data[i] = Convert.ToString(rebuff[i], 16).ToUpper(); //显示十六进制大写数据
str = data[i];
if (str.Length == 1)
{
str = "0" + str;
}
textBox2.AppendText(str);
}
}
private void button3_Click(object sender, EventArgs e) //清除数据
{
try
{
textBox2.Text = "";
}
catch
{
MessageBox.Show("清除接收区数据错误", "error");
}
}
public byte[] crc16(byte[] data,int Length) //CRC16校验
{
byte i,j;
int crc16=0xFFFF;
for(i=0;i<Length;i++)
{
crc16^=data[i];
for(j = 0; j < 8; j++)
{
if((crc16&0x01)==1)
{
crc16=(crc16>>1)^0xA001;
}
else
crc16=crc16>>1;
}
}
returndata = new byte[2] { (byte)(crc16 & 0xFF), (byte)(crc16 >> 8) };
return returndata;
}
private void button4_Click(object sender, EventArgs e) //关闭串口
{

ovalShape1.FillColor = Color.White;
serialPort1.Close();
timer1.Stop();
}
private void timer1_Tick(object sender, EventArgs e) //定时器
{
count++;
if (count == 10)
{
senddata();
count = 0;
}
}
}
}
...全文
1001 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
wjh19900506 2015-04-13
  • 打赏
  • 举报
回复
CRC16校验是没有问题,我读单片机一个通道的数据是对的,而且这个校验码和我经常使用的串口助手产生的校验码是一样的,应该不是校验码的问题!我读一个通道的数据,单片机返回7个字节,我上位机正确收到正确的数据,我读2个通道就不行了,最多只能返回8个字节的数据!
於黾 2015-04-13
  • 打赏
  • 举报
回复
buff[0] = 0x01; buff[1] = 0x03; buff[2] = 0x00; buff[3] = 0x00; buff[4] = 0x00; buff[5] = 0x01; crc16(buff,6); buff[6] = returndata[0]; buff[7] = returndata[1]; 很明显你的crc16函数写的有问题 根本没有获取返回值,returndata[0]和returndata[1]永远是初始值,所以校验错误,单片机收不到正确的数据,给你返回的是个8字节的错误码,而不是数据 要么returndata=crc16(buff,6); 先获取计算好的crc校验值,再赋值 要么修改crc16这个函数,直接在函数里给buff[6]和buff[7]赋值
dongdongdongJL 2015-04-13
  • 打赏
  • 举报
回复
我也正在搞串口!希望一起弄!共勉!
卧_槽 2015-04-13
  • 打赏
  • 举报
回复
串口大部分时候需要自己对接收到的消息进行完整性判断,串口是比较低级的IO接口,没办法知道输入消息什么时候是一条。
KJ_Wang 2015-04-13
  • 打赏
  • 举报
回复
先用Windows客户端试试呀!
wjh19900506 2015-04-12
  • 打赏
  • 举报
回复
接收的数据是发送数据决定字节数的,所以不能用SerialPort.ReceivedBytesThreshold = length,这段代码的疑问就是接收字节数最大只能是8(单片机回复的(串口助手显示单片机数据回复是正常的)),而我上位机发,短接AB线,是能够收到完整的数据!就是不知道为什么和单片机通信回复就不能超过8个字节!
  • 打赏
  • 举报
回复
处理 DataReceived 事件,你可以判断系统缓冲区里的数据的个数不足一个消息时就不去做任何处理,你也可以把它取出来放到自己的应用程序另一个跟大的缓冲区里。总之不是在每一次 DataReceived 事件处理时去调用 display 方法的!(当然你也根本没有必要写 Invoke 语句去调用 display 方法,而应该直接调用它)
  • 打赏
  • 举报
回复
你的代码中的 Thread.Sleep(100)、Thread.Sleep(300),让人看到你的编程的“无奈”。 正常的程序根本不用不靠谱的“延时”。你这种延时是瞎猜、祈求一个延时,它(100毫秒、300毫秒)有准吗?
  • 打赏
  • 举报
回复
许多早期的串行通讯协议,都是以EOF作为消息结束符号的。 当你设置了 ReceivedBytesThreshold 参数以后,就算是能够保证缓冲区里边有超过15个字符才触发事件(而不是有8个字符就触发),你也不能假设缓冲区正好是15个字符而没有多出来一两个字符(下一个消息的开头字符)。 因此,最可取的做法,是要能够知道处理“多次处理 DataReceived 事件来取得(分割)消息”,而不是以为每一次 DataReceived 事件触发时一定有完整的一个消息。
学飞的笨鸟 2015-04-12
  • 打赏
  • 举报
回复
如果接收数据是定长len的话 ,可以设置"SerialPort.ReceivedBytesThreshold = len"试下
zhouzhou1994 2015-04-11
  • 打赏
  • 举报
回复
System.Threading.Thread.Sleep(300); //延时 length = serialPort1.BytesToRead; //获取缓冲区字节数 serialPort1.Read(rebuff, 0, length); //读数据 这个地方,你应该是接收完一帧,而不是一次就重新开始存数据了。因为串口触发之后,你的延时可能不是所有数据都进来了。

110,536

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧